Add comprehensive installation and setup documentation

- Add GETTING_STARTED.md with quick start guide and development modes
- Add INSTALL.sh automated installation script
- Add INSTALLATION_CHECKLIST.md, INSTALLATION_SUCCESS.md, and INSTALLATION_SUMMARY.md
- Add QUICK_REFERENCE.md for common commands
- Add SETUP_GUIDE.md with detailed setup instructions
- Update README.md with improved project overview
- Add did-wallet app dependencies and node_modules
This commit is contained in:
Dorian
2026-01-27 17:18:21 +00:00
parent a81f655133
commit 0d073fa89e
22658 changed files with 4494151 additions and 6 deletions
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+1
View File
@@ -0,0 +1 @@
# Web5 DID
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
{"type": "commonjs"}
+245
View File
@@ -0,0 +1,245 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// dist/esm/utils.js
var utils_exports = {};
__export(utils_exports, {
extractDidFragment: () => extractDidFragment,
getServices: () => getServices,
getVerificationMethodByKey: () => getVerificationMethodByKey,
getVerificationMethodTypes: () => getVerificationMethodTypes,
getVerificationMethods: () => getVerificationMethods,
getVerificationRelationshipsById: () => getVerificationRelationshipsById,
isDidService: () => isDidService,
isDidVerificationMethod: () => isDidVerificationMethod,
isDwnDidService: () => isDwnDidService,
keyBytesToMultibaseId: () => keyBytesToMultibaseId,
multibaseIdToKeyBytes: () => multibaseIdToKeyBytes
});
module.exports = __toCommonJS(utils_exports);
var import_common = require("@web5/common");
var import_crypto = require("@web5/crypto");
// dist/esm/did-error.js
var DidError = class _DidError extends Error {
/**
* Constructs an instance of DidError, a custom error class for handling DID-related errors.
*
* @param code - A {@link DidErrorCode} representing the specific type of error encountered.
* @param message - A human-readable description of the error.
*/
constructor(code, message) {
super(`${code}: ${message}`);
this.code = code;
this.name = "DidError";
Object.setPrototypeOf(this, new.target.prototype);
if (Error.captureStackTrace) {
Error.captureStackTrace(this, _DidError);
}
}
};
var DidErrorCode;
(function(DidErrorCode2) {
DidErrorCode2["InvalidDid"] = "invalidDid";
DidErrorCode2["MethodNotSupported"] = "methodNotSupported";
DidErrorCode2["InternalError"] = "internalError";
DidErrorCode2["InvalidDidDocument"] = "invalidDidDocument";
DidErrorCode2["InvalidDidDocumentLength"] = "invalidDidDocumentLength";
DidErrorCode2["InvalidDidUrl"] = "invalidDidUrl";
DidErrorCode2["InvalidPreviousDidProof"] = "invalidPreviousDidProof";
DidErrorCode2["InvalidPublicKey"] = "invalidPublicKey";
DidErrorCode2["InvalidPublicKeyLength"] = "invalidPublicKeyLength";
DidErrorCode2["InvalidPublicKeyType"] = "invalidPublicKeyType";
DidErrorCode2["InvalidSignature"] = "invalidSignature";
DidErrorCode2["NotFound"] = "notFound";
DidErrorCode2["RepresentationNotSupported"] = "representationNotSupported";
DidErrorCode2["UnsupportedPublicKeyType"] = "unsupportedPublicKeyType";
})(DidErrorCode || (DidErrorCode = {}));
// dist/esm/types/did-core.js
var DidVerificationRelationship;
(function(DidVerificationRelationship2) {
DidVerificationRelationship2["authentication"] = "authentication";
DidVerificationRelationship2["assertionMethod"] = "assertionMethod";
DidVerificationRelationship2["keyAgreement"] = "keyAgreement";
DidVerificationRelationship2["capabilityInvocation"] = "capabilityInvocation";
DidVerificationRelationship2["capabilityDelegation"] = "capabilityDelegation";
})(DidVerificationRelationship || (DidVerificationRelationship = {}));
// dist/esm/utils.js
var __awaiter = function(thisArg, _arguments, P, generator) {
function adopt(value) {
return value instanceof P ? value : new P(function(resolve) {
resolve(value);
});
}
return new (P || (P = Promise))(function(resolve, reject) {
function fulfilled(value) {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
}
function rejected(value) {
try {
step(generator["throw"](value));
} catch (e) {
reject(e);
}
}
function step(result) {
result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
}
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
function extractDidFragment(input) {
if (typeof input !== "string")
return void 0;
if (input.length === 0)
return void 0;
return input.split("#").pop();
}
function getServices({ didDocument, id, type }) {
var _a, _b;
return (_b = (_a = didDocument === null || didDocument === void 0 ? void 0 : didDocument.service) === null || _a === void 0 ? void 0 : _a.filter((service) => {
if (id && service.id !== id)
return false;
if (type && service.type !== type)
return false;
return true;
})) !== null && _b !== void 0 ? _b : [];
}
function getVerificationMethodByKey(_a) {
return __awaiter(this, arguments, void 0, function* ({ didDocument, publicKeyJwk, publicKeyMultibase }) {
const verificationMethods = getVerificationMethods({ didDocument });
for (let method of verificationMethods) {
if (publicKeyJwk && method.publicKeyJwk) {
const publicKeyThumbprint = yield (0, import_crypto.computeJwkThumbprint)({ jwk: publicKeyJwk });
if (publicKeyThumbprint === (yield (0, import_crypto.computeJwkThumbprint)({ jwk: method.publicKeyJwk }))) {
return method;
}
} else if (publicKeyMultibase && method.publicKeyMultibase) {
if (publicKeyMultibase === method.publicKeyMultibase) {
return method;
}
}
}
return null;
});
}
function getVerificationMethods({ didDocument }) {
var _a, _b;
if (!didDocument)
throw new TypeError(`Required parameter missing: 'didDocument'`);
const verificationMethods = [];
verificationMethods.push(...(_b = (_a = didDocument.verificationMethod) === null || _a === void 0 ? void 0 : _a.filter(isDidVerificationMethod)) !== null && _b !== void 0 ? _b : []);
Object.keys(DidVerificationRelationship).forEach((relationship) => {
var _a2, _b2;
verificationMethods.push(...(_b2 = (_a2 = didDocument[relationship]) === null || _a2 === void 0 ? void 0 : _a2.filter(isDidVerificationMethod)) !== null && _b2 !== void 0 ? _b2 : []);
});
return verificationMethods;
}
function getVerificationMethodTypes({ didDocument }) {
const verificationMethods = getVerificationMethods({ didDocument });
const types = verificationMethods.map((method) => method.type);
return [...new Set(types)];
}
function getVerificationRelationshipsById({ didDocument, methodId }) {
const relationships = [];
Object.keys(DidVerificationRelationship).forEach((relationship) => {
if (Array.isArray(didDocument[relationship])) {
const relationshipMethods = didDocument[relationship];
const methodIdFragment = extractDidFragment(methodId);
const containsMethodId = relationshipMethods.some((method) => {
const isByReferenceMatch = extractDidFragment(method) === methodIdFragment;
const isEmbeddedMethodMatch = isDidVerificationMethod(method) && extractDidFragment(method.id) === methodIdFragment;
return isByReferenceMatch || isEmbeddedMethodMatch;
});
if (containsMethodId) {
relationships.push(relationship);
}
}
});
return relationships;
}
function isDidService(obj) {
if (!obj || typeof obj !== "object" || obj === null)
return false;
return "id" in obj && "type" in obj && "serviceEndpoint" in obj;
}
function isDwnDidService(obj) {
if (!isDidService(obj))
return false;
if (obj.type !== "DecentralizedWebNode")
return false;
if (!("enc" in obj && "sig" in obj))
return false;
const isStringOrStringArray = (prop) => typeof prop === "string" || Array.isArray(prop) && prop.every((item) => typeof item === "string");
return isStringOrStringArray(obj.enc) && isStringOrStringArray(obj.sig);
}
function isDidVerificationMethod(obj) {
if (!obj || typeof obj !== "object" || obj === null)
return false;
if (!("id" in obj && "type" in obj && "controller" in obj))
return false;
if (typeof obj.id !== "string")
return false;
if (typeof obj.type !== "string")
return false;
if (typeof obj.controller !== "string")
return false;
return true;
}
function keyBytesToMultibaseId({ keyBytes, multicodecCode, multicodecName }) {
const prefixedKey = import_common.Multicodec.addPrefix({
code: multicodecCode,
data: keyBytes,
name: multicodecName
});
const prefixedKeyB58 = import_common.Convert.uint8Array(prefixedKey).toBase58Btc();
const multibaseKeyId = import_common.Convert.base58Btc(prefixedKeyB58).toMultibase();
return multibaseKeyId;
}
function multibaseIdToKeyBytes({ multibaseKeyId }) {
try {
const prefixedKeyB58 = import_common.Convert.multibase(multibaseKeyId).toBase58Btc();
const prefixedKey = import_common.Convert.base58Btc(prefixedKeyB58).toUint8Array();
const { code, data, name } = import_common.Multicodec.removePrefix({ prefixedData: prefixedKey });
return { keyBytes: data, multicodecCode: code, multicodecName: name };
} catch (error) {
throw new DidError(DidErrorCode.InvalidDid, `Invalid multibase identifier: ${multibaseKeyId}`);
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
extractDidFragment,
getServices,
getVerificationMethodByKey,
getVerificationMethodTypes,
getVerificationMethods,
getVerificationRelationshipsById,
isDidService,
isDidVerificationMethod,
isDwnDidService,
keyBytesToMultibaseId,
multibaseIdToKeyBytes
});
//# sourceMappingURL=utils.js.map
File diff suppressed because one or more lines are too long
+196
View File
@@ -0,0 +1,196 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { LocalKeyManager, utils as cryptoUtils } from '@web5/crypto';
import { DidError, DidErrorCode } from './did-error.js';
import { extractDidFragment, getVerificationMethods } from './utils.js';
/**
* Represents a Decentralized Identifier (DID) along with its DID document, key manager, metadata,
* and convenience functions.
*/
export class BearerDid {
constructor({ uri, document, metadata, keyManager }) {
this.uri = uri;
this.document = document;
this.metadata = metadata;
this.keyManager = keyManager;
}
/**
* Converts a `BearerDid` object to a portable format containing the URI and verification methods
* associated with the DID.
*
* This method is useful when you need to represent the key material and metadata associated with
* a DID in format that can be used independently of the specific DID method implementation. It
* extracts both public and private keys from the DID's key manager and organizes them into a
* `PortableDid` structure.
*
* @remarks
* If the DID's key manager does not allow private keys to be exported, the `PortableDid` returned
* will not contain a `privateKeys` property. This enables the importing and exporting DIDs that
* use the same underlying KMS even if the KMS does not support exporting private keys. Examples
* include hardware security modules (HSMs) and cloud-based KMS services like AWS KMS.
*
* If the DID's key manager does support exporting private keys, the resulting `PortableDid` will
* include a `privateKeys` property which contains the same number of entries as there are
* verification methods as the DID document, each with its associated private key and the
* purpose(s) for which the key can be used (e.g., `authentication`, `assertionMethod`, etc.).
*
* @example
* ```ts
* // Assuming `did` is an instance of BearerDid
* const portableDid = await did.export();
* // portableDid now contains the DID URI, document, metadata, and optionally, private keys.
* ```
*
* @returns A `PortableDid` containing the URI, DID document, metadata, and optionally private
* keys associated with the `BearerDid`.
* @throws An error if the DID document does not contain any verification methods or the keys for
* any verification method are missing in the key manager.
*/
export() {
return __awaiter(this, void 0, void 0, function* () {
// Verify the DID document contains at least one verification method.
if (!(Array.isArray(this.document.verificationMethod) && this.document.verificationMethod.length > 0)) {
throw new Error(`DID document for '${this.uri}' is missing verification methods`);
}
// Create a new `PortableDid` object to store the exported data.
let portableDid = {
uri: this.uri,
document: this.document,
metadata: this.metadata
};
// If the BearerDid's key manager supports exporting private keys, add them to the portable DID.
if ('exportKey' in this.keyManager && typeof this.keyManager.exportKey === 'function') {
const privateKeys = [];
for (let vm of this.document.verificationMethod) {
if (!vm.publicKeyJwk) {
throw new Error(`Verification method '${vm.id}' does not contain a public key in JWK format`);
}
// Compute the key URI of the verification method's public key.
const keyUri = yield this.keyManager.getKeyUri({ key: vm.publicKeyJwk });
// Retrieve the private key from the key manager.
const privateKey = yield this.keyManager.exportKey({ keyUri });
// Add the verification method to the key set.
privateKeys.push(Object.assign({}, privateKey));
}
portableDid.privateKeys = privateKeys;
}
return portableDid;
});
}
/**
* Return a {@link Signer} that can be used to sign messages, credentials, or arbitrary data.
*
* If given, the `methodId` parameter is used to select a key from the verification methods
* present in the DID Document.
*
* If `methodID` is not given, the first verification method intended for signing claims is used.
*
* @param params - The parameters for the `getSigner` operation.
* @param params.methodId - ID of the verification method key that will be used for sign and
* verify operations. Optional.
* @returns An instantiated {@link Signer} that can be used to sign and verify data.
*/
getSigner(params) {
return __awaiter(this, void 0, void 0, function* () {
var _a;
// Attempt to find a verification method that matches the given method ID, or if not given,
// find the first verification method intended for signing claims.
const verificationMethod = (_a = this.document.verificationMethod) === null || _a === void 0 ? void 0 : _a.find(vm => { var _a, _b; return extractDidFragment(vm.id) === ((_a = extractDidFragment(params === null || params === void 0 ? void 0 : params.methodId)) !== null && _a !== void 0 ? _a : extractDidFragment((_b = this.document.assertionMethod) === null || _b === void 0 ? void 0 : _b[0])); });
if (!(verificationMethod && verificationMethod.publicKeyJwk)) {
throw new DidError(DidErrorCode.InternalError, 'A verification method intended for signing could not be determined from the DID Document');
}
// Compute the expected key URI of the signing key.
const keyUri = yield this.keyManager.getKeyUri({ key: verificationMethod.publicKeyJwk });
// Get the public key to be used for verify operations, which also verifies that the key is
// present in the key manager's store.
const publicKey = yield this.keyManager.getPublicKey({ keyUri });
// Bind the DID's key manager to the signer.
const keyManager = this.keyManager;
// Determine the signing algorithm.
const algorithm = cryptoUtils.getJoseSignatureAlgorithmFromPublicKey(publicKey);
return {
algorithm: algorithm,
keyId: verificationMethod.id,
sign(_a) {
return __awaiter(this, arguments, void 0, function* ({ data }) {
const signature = yield keyManager.sign({ data, keyUri: keyUri }); // `keyUri` is guaranteed to be defined at this point.
return signature;
});
},
verify(_a) {
return __awaiter(this, arguments, void 0, function* ({ data, signature }) {
const isValid = yield keyManager.verify({ data, key: publicKey, signature }); // `publicKey` is guaranteed to be defined at this point.
return isValid;
});
}
};
});
}
/**
* Instantiates a {@link BearerDid} object from a given {@link PortableDid}.
*
* This method allows for the creation of a `BearerDid` object using a previously created DID's
* key material, DID document, and metadata.
*
* @example
* ```ts
* // Export an existing BearerDid to PortableDid format.
* const portableDid = await did.export();
* // Reconstruct a BearerDid object from the PortableDid.
* const did = await BearerDid.import({ portableDid });
* ```
*
* @param params - The parameters for the import operation.
* @param params.portableDid - The PortableDid object to import.
* @param params.keyManager - Optionally specify an external Key Management System (KMS) used to
* generate keys and sign data. If not given, a new
* {@link LocalKeyManager} instance will be created and
* used.
* @returns A Promise resolving to a `BearerDid` object representing the DID formed from the
* provided PortableDid.
* @throws An error if the PortableDid document does not contain any verification methods or the
* keys for any verification method are missing in the key manager.
*/
static import(_a) {
return __awaiter(this, arguments, void 0, function* ({ portableDid, keyManager = new LocalKeyManager() }) {
var _b;
// Get all verification methods from the given DID document, including embedded methods.
const verificationMethods = getVerificationMethods({ didDocument: portableDid.document });
// Validate that the DID document contains at least one verification method.
if (verificationMethods.length === 0) {
throw new DidError(DidErrorCode.InvalidDidDocument, `At least one verification method is required but 0 were given`);
}
// If given, import the private key material into the key manager.
for (let key of (_b = portableDid.privateKeys) !== null && _b !== void 0 ? _b : []) {
yield keyManager.importKey({ key });
}
// Validate that the key material for every verification method in the DID document is present
// in the key manager.
for (let vm of verificationMethods) {
if (!vm.publicKeyJwk) {
throw new Error(`Verification method '${vm.id}' does not contain a public key in JWK format`);
}
// Compute the key URI of the verification method's public key.
const keyUri = yield keyManager.getKeyUri({ key: vm.publicKeyJwk });
// Verify that the key is present in the key manager. If not, an error is thrown.
yield keyManager.getPublicKey({ keyUri });
}
// Use the given PortableDid to construct the BearerDid object.
const did = new BearerDid({
uri: portableDid.uri,
document: portableDid.document,
metadata: portableDid.metadata,
keyManager
});
return did;
});
}
}
//# sourceMappingURL=bearer-did.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"bearer-did.js","sourceRoot":"","sources":["../../src/bearer-did.ts"],"names":[],"mappings":"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"}
+62
View File
@@ -0,0 +1,62 @@
/**
* A custom error class for DID-related errors.
*/
export class DidError extends Error {
/**
* Constructs an instance of DidError, a custom error class for handling DID-related errors.
*
* @param code - A {@link DidErrorCode} representing the specific type of error encountered.
* @param message - A human-readable description of the error.
*/
constructor(code, message) {
super(`${code}: ${message}`);
this.code = code;
this.name = 'DidError';
// Ensures that instanceof works properly, the correct prototype chain when using inheritance,
// and that V8 stack traces (like Chrome, Edge, and Node.js) are more readable and relevant.
Object.setPrototypeOf(this, new.target.prototype);
// Captures the stack trace in V8 engines (like Chrome, Edge, and Node.js).
// In non-V8 environments, the stack trace will still be captured.
if (Error.captureStackTrace) {
Error.captureStackTrace(this, DidError);
}
}
}
/**
* An enumeration of possible DID error codes.
*/
export var DidErrorCode;
(function (DidErrorCode) {
/** The DID supplied does not conform to valid syntax. */
DidErrorCode["InvalidDid"] = "invalidDid";
/** The supplied method name is not supported by the DID method and/or DID resolver implementation. */
DidErrorCode["MethodNotSupported"] = "methodNotSupported";
/** An unexpected error occurred during the requested DID operation. */
DidErrorCode["InternalError"] = "internalError";
/** The DID document supplied does not conform to valid syntax. */
DidErrorCode["InvalidDidDocument"] = "invalidDidDocument";
/** The byte length of a DID document does not match the expected value. */
DidErrorCode["InvalidDidDocumentLength"] = "invalidDidDocumentLength";
/** The DID URL supplied to the dereferencing function does not conform to valid syntax. */
DidErrorCode["InvalidDidUrl"] = "invalidDidUrl";
/** The given proof of a previous DID is invalid */
DidErrorCode["InvalidPreviousDidProof"] = "invalidPreviousDidProof";
/** An invalid public key is detected during a DID operation. */
DidErrorCode["InvalidPublicKey"] = "invalidPublicKey";
/** The byte length of a public key does not match the expected value. */
DidErrorCode["InvalidPublicKeyLength"] = "invalidPublicKeyLength";
/** An invalid public key type was detected during a DID operation. */
DidErrorCode["InvalidPublicKeyType"] = "invalidPublicKeyType";
/** Verification of a signature failed during a DID operation. */
DidErrorCode["InvalidSignature"] = "invalidSignature";
/** The DID resolver was unable to find the DID document resulting from the resolution request. */
DidErrorCode["NotFound"] = "notFound";
/**
* The representation requested via the `accept` input metadata property is not supported by the
* DID method and/or DID resolver implementation.
*/
DidErrorCode["RepresentationNotSupported"] = "representationNotSupported";
/** The type of a public key is not supported by the DID method and/or DID resolver implementation. */
DidErrorCode["UnsupportedPublicKeyType"] = "unsupportedPublicKeyType";
})(DidErrorCode || (DidErrorCode = {}));
//# sourceMappingURL=did-error.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"did-error.js","sourceRoot":"","sources":["../../src/did-error.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,QAAS,SAAQ,KAAK;IACjC;;;;;OAKG;IACH,YAAmB,IAAkB,EAAE,OAAe;QACpD,KAAK,CAAC,GAAG,IAAI,KAAK,OAAO,EAAE,CAAC,CAAC;QADZ,SAAI,GAAJ,IAAI,CAAc;QAEnC,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;QAEvB,8FAA8F;QAC9F,4FAA4F;QAC5F,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAElD,2EAA2E;QAC3E,kEAAkE;QAClE,IAAI,KAAK,CAAC,iBAAiB,EAAE,CAAC;YAC5B,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC;CACF;AAED;;GAEG;AACH,MAAM,CAAN,IAAY,YA6CX;AA7CD,WAAY,YAAY;IACtB,yDAAyD;IACzD,yCAAyB,CAAA;IAEzB,sGAAsG;IACtG,yDAAyC,CAAA;IAEzC,uEAAuE;IACvE,+CAA+B,CAAA;IAE/B,kEAAkE;IAClE,yDAAyC,CAAA;IAEzC,2EAA2E;IAC3E,qEAAqD,CAAA;IAErD,2FAA2F;IAC3F,+CAA+B,CAAA;IAE/B,mDAAmD;IACnD,mEAAmD,CAAA;IAEnD,gEAAgE;IAChE,qDAAqC,CAAA;IAErC,yEAAyE;IACzE,iEAAiD,CAAA;IAEjD,sEAAsE;IACtE,6DAA6C,CAAA;IAE7C,iEAAiE;IACjE,qDAAqC,CAAA;IAErC,kGAAkG;IAClG,qCAAqB,CAAA;IAErB;;;OAGG;IACH,yEAAyD,CAAA;IAEzD,sGAAsG;IACtG,qEAAqD,CAAA;AACvD,CAAC,EA7CW,YAAY,KAAZ,YAAY,QA6CvB"}
+114
View File
@@ -0,0 +1,114 @@
/**
* The `Did` class represents a Decentralized Identifier (DID) Uniform Resource Identifier (URI).
*
* This class provides a method for parsing a DID URI string into its component parts, as well as a
* method for serializing a DID URI object into a string.
*
* A DID URI is composed of the following components:
* - scheme
* - method
* - id
* - path
* - query
* - fragment
* - params
*
* @see {@link https://www.w3.org/TR/did-core/#did-syntax | DID Core Specification, § DID Syntax}
*/
export class Did {
/**
* Constructs a new `Did` instance from individual components.
*
* @param params - An object containing the parameters to be included in the DID URI.
* @param params.method - The name of the DID method.
* @param params.id - The DID method identifier.
* @param params.path - Optional. The path component of the DID URI.
* @param params.query - Optional. The query component of the DID URI.
* @param params.fragment - Optional. The fragment component of the DID URI.
* @param params.params - Optional. The query parameters in the DID URI.
*/
constructor({ method, id, path, query, fragment, params }) {
this.uri = `did:${method}:${id}`;
this.method = method;
this.id = id;
this.path = path;
this.query = query;
this.fragment = fragment;
this.params = params;
}
/**
* Parses a DID URI string into its individual components.
*
* @example
* ```ts
* const did = Did.parse('did:example:123?service=agent&relativeRef=/credentials#degree');
*
* console.log(did.uri) // Output: 'did:example:123'
* console.log(did.method) // Output: 'example'
* console.log(did.id) // Output: '123'
* console.log(did.query) // Output: 'service=agent&relativeRef=/credentials'
* console.log(did.fragment) // Output: 'degree'
* console.log(did.params) // Output: { service: 'agent', relativeRef: '/credentials' }
* ```
*
* @params didUri - The DID URI string to be parsed.
* @returns A `Did` object representing the parsed DID URI, or `null` if the input string is not a valid DID URI.
*/
static parse(didUri) {
// Return null if the input string is empty or not provided.
if (!didUri)
return null;
// Execute the regex pattern on the input string to extract URI components.
const match = Did.DID_URI_PATTERN.exec(didUri);
// If the pattern does not match, or if the required groups are not found, return null.
if (!match || !match.groups)
return null;
// Extract the method, id, params, path, query, and fragment from the regex match groups.
const { method, id, path, query, fragment } = match.groups;
// Initialize a new Did object with the uri, method and id.
const did = {
uri: `did:${method}:${id}`,
method,
id,
};
// If path is present, add it to the Did object.
if (path)
did.path = path;
// If query is present, add it to the Did object, removing the leading '?'.
if (query)
did.query = query.slice(1);
// If fragment is present, add it to the Did object, removing the leading '#'.
if (fragment)
did.fragment = fragment.slice(1);
// If query params are present, parse them into a key-value object and add to the Did object.
if (query) {
const parsedParams = {};
// Split the query string by '&' to get individual parameter strings.
const paramPairs = query.slice(1).split('&');
for (const pair of paramPairs) {
// Split each parameter string by '=' to separate keys and values.
const [key, value] = pair.split('=');
parsedParams[key] = value;
}
did.params = parsedParams;
}
return did;
}
}
/** Regular expression pattern for matching the method component of a DID URI. */
Did.METHOD_PATTERN = '([a-z0-9]+)';
/** Regular expression pattern for matching percent-encoded characters in a method identifier. */
Did.PCT_ENCODED_PATTERN = '(?:%[0-9a-fA-F]{2})';
/** Regular expression pattern for matching the characters allowed in a method identifier. */
Did.ID_CHAR_PATTERN = `(?:[a-zA-Z0-9._-]|${Did.PCT_ENCODED_PATTERN})`;
/** Regular expression pattern for matching the method identifier component of a DID URI. */
Did.METHOD_ID_PATTERN = `((?:${Did.ID_CHAR_PATTERN}*:)*(${Did.ID_CHAR_PATTERN}+))`;
/** Regular expression pattern for matching the path component of a DID URI. */
Did.PATH_PATTERN = `(/[^#?]*)?`;
/** Regular expression pattern for matching the query component of a DID URI. */
Did.QUERY_PATTERN = `([?][^#]*)?`;
/** Regular expression pattern for matching the fragment component of a DID URI. */
Did.FRAGMENT_PATTERN = `(#.*)?`;
/** Regular expression pattern for matching all of the components of a DID URI. */
Did.DID_URI_PATTERN = new RegExp(`^did:(?<method>${Did.METHOD_PATTERN}):(?<id>${Did.METHOD_ID_PATTERN})(?<path>${Did.PATH_PATTERN})(?<query>${Did.QUERY_PATTERN})(?<fragment>${Did.FRAGMENT_PATTERN})$`);
//# sourceMappingURL=did.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"did.js","sourceRoot":"","sources":["../../src/did.ts"],"names":[],"mappings":"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"}
+16
View File
@@ -0,0 +1,16 @@
export * from './types/did-core.js';
export * from './types/did-resolution.js';
export * from './did.js';
export * from './did-error.js';
export * from './bearer-did.js';
export * from './methods/did-dht.js';
export * from './methods/did-ion.js';
export * from './methods/did-jwk.js';
export * from './methods/did-key.js';
export * from './methods/did-method.js';
export * from './methods/did-web.js';
export * from './resolver/resolver-cache-level.js';
export * from './resolver/resolver-cache-noop.js';
export * from './resolver/universal-resolver.js';
export * as utils from './utils.js';
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAI1C,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAEhC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AAErC,cAAc,oCAAoC,CAAC;AACnD,cAAc,mCAAmC,CAAC;AAClD,cAAc,kCAAkC,CAAC;AAEjD,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC"}
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+570
View File
@@ -0,0 +1,570 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { IonDid, IonRequest } from '@decentralized-identity/ion-sdk';
import { LocalKeyManager, computeJwkThumbprint } from '@web5/crypto';
import { Did } from '../did.js';
import { BearerDid } from '../bearer-did.js';
import { DidMethod } from '../methods/did-method.js';
import { DidError, DidErrorCode } from '../did-error.js';
import { getVerificationRelationshipsById } from '../utils.js';
import { EMPTY_DID_RESOLUTION_RESULT } from '../types/did-resolution.js';
/**
* Enumerates the types of keys that can be used in a DID ION document.
*
* The DID ION method supports various cryptographic key types. These key types are essential for
* the creation and management of DIDs and their associated cryptographic operations like signing
* and encryption.
*/
export var DidIonRegisteredKeyType;
(function (DidIonRegisteredKeyType) {
/**
* Ed25519: A public-key signature system using the EdDSA (Edwards-curve Digital Signature
* Algorithm) and Curve25519.
*/
DidIonRegisteredKeyType["Ed25519"] = "Ed25519";
/**
* secp256k1: A cryptographic curve used for digital signatures in a range of decentralized
* systems.
*/
DidIonRegisteredKeyType["secp256k1"] = "secp256k1";
/**
* secp256r1: Also known as P-256 or prime256v1, this curve is used for cryptographic operations
* and is widely supported in various cryptographic libraries and standards.
*/
DidIonRegisteredKeyType["secp256r1"] = "secp256r1";
/**
* X25519: A Diffie-Hellman key exchange algorithm using Curve25519.
*/
DidIonRegisteredKeyType["X25519"] = "X25519";
})(DidIonRegisteredKeyType || (DidIonRegisteredKeyType = {}));
/**
* Private helper that maps algorithm identifiers to their corresponding DID ION
* {@link DidIonRegisteredKeyType | registered key type}.
*/
const AlgorithmToKeyTypeMap = {
Ed25519: DidIonRegisteredKeyType.Ed25519,
ES256K: DidIonRegisteredKeyType.secp256k1,
ES256: DidIonRegisteredKeyType.secp256r1,
'P-256': DidIonRegisteredKeyType.secp256r1,
secp256k1: DidIonRegisteredKeyType.secp256k1,
secp256r1: DidIonRegisteredKeyType.secp256r1
};
/**
* The default node to use as a gateway to the Sidetree newtork when anchoring, updating, and
* resolving DID documents.
*/
const DEFAULT_GATEWAY_URI = 'https://ion.tbd.engineering';
/**
* The `DidIon` class provides an implementation of the `did:ion` DID method.
*
* Features:
* - DID Creation: Create new `did:ion` DIDs.
* - DID Key Management: Instantiate a DID object from an existing key in a Key Management System
* (KMS). If supported by the KMS, a DID's key can be exported to a portable
* DID format.
* - DID Resolution: Resolve a `did:ion` to its corresponding DID Document stored in the Sidetree
* network.
* - Signature Operations: Sign and verify messages using keys associated with a DID.
*
* @see {@link https://identity.foundation/sidetree/spec/ | Sidetree Protocol Specification}
* @see {@link https://github.com/decentralized-identity/ion/blob/master/docs/design.md | ION Design Document}
*
* @example
* ```ts
* // DID Creation
* const did = await DidIon.create();
*
* // DID Creation with a KMS
* const keyManager = new LocalKeyManager();
* const did = await DidIon.create({ keyManager });
*
* // DID Resolution
* const resolutionResult = await DidIon.resolve({ did: did.uri });
*
* // Signature Operations
* const signer = await did.getSigner();
* const signature = await signer.sign({ data: new TextEncoder().encode('Message') });
* const isValid = await signer.verify({ data: new TextEncoder().encode('Message'), signature });
*
* // Key Management
*
* // Instantiate a DID object for a published DID with existing keys in a KMS
* const did = await DidIon.fromKeyManager({
* didUri: 'did:ion:EiAzB7K-xDIKc1csXo5HX2eNBoemK9feNhL3cKwfukYOug',
* keyManager
* });
*
* // Convert a DID object to a portable format
* const portableDid = await DidIon.toKeys({ did });
* ```
*/
export class DidIon extends DidMethod {
/**
* Creates a new DID using the `did:ion` method formed from a newly generated key.
*
* Notes:
* - If no `options` are given, by default a new Ed25519 key will be generated.
*
* @example
* ```ts
* // DID Creation
* const did = await DidIon.create();
*
* // DID Creation with a KMS
* const keyManager = new LocalKeyManager();
* const did = await DidIon.create({ keyManager });
* ```
*
* @param params - The parameters for the create operation.
* @param params.keyManager - Optionally specify a Key Management System (KMS) used to generate
* keys and sign data.
* @param params.options - Optional parameters that can be specified when creating a new DID.
* @returns A Promise resolving to a {@link BearerDid} object representing the new DID.
*/
static create() {
return __awaiter(this, arguments, void 0, function* ({ keyManager = new LocalKeyManager(), options = {} } = {}) {
// Before processing the create operation, validate DID-method-specific requirements to prevent
// keys from being generated unnecessarily.
var _a, _b, _c, _d, _e, _f, _g;
// Check 1: Validate that the algorithm for any given verification method is supported by the
// DID ION specification.
if ((_a = options.verificationMethods) === null || _a === void 0 ? void 0 : _a.some(vm => !(vm.algorithm in AlgorithmToKeyTypeMap))) {
throw new Error('One or more verification method algorithms are not supported');
}
// Check 2: Validate that the ID for any given verification method is unique.
const methodIds = (_b = options.verificationMethods) === null || _b === void 0 ? void 0 : _b.filter(vm => 'id' in vm).map(vm => vm.id);
if (methodIds && methodIds.length !== new Set(methodIds).size) {
throw new Error('One or more verification method IDs are not unique');
}
// Check 3: Validate that the required properties for any given services are present.
if ((_c = options.services) === null || _c === void 0 ? void 0 : _c.some(s => !s.id || !s.type || !s.serviceEndpoint)) {
throw new Error('One or more services are missing required properties');
}
// If no verification methods were specified, generate a default Ed25519 verification method.
const defaultVerificationMethod = {
algorithm: 'Ed25519',
purposes: ['authentication', 'assertionMethod', 'capabilityDelegation', 'capabilityInvocation']
};
const verificationMethodsToAdd = [];
// Generate random key material for additional verification methods, if any.
for (const vm of (_d = options.verificationMethods) !== null && _d !== void 0 ? _d : [defaultVerificationMethod]) {
// Generate a random key for the verification method.
const keyUri = yield keyManager.generateKey({ algorithm: vm.algorithm });
const publicKey = yield keyManager.getPublicKey({ keyUri });
// Add the verification method to the DID document.
verificationMethodsToAdd.push({
id: vm.id,
publicKeyJwk: publicKey,
purposes: (_e = vm.purposes) !== null && _e !== void 0 ? _e : ['authentication', 'assertionMethod', 'capabilityDelegation', 'capabilityInvocation']
});
}
// Generate a random key for the ION Recovery Key. Sidetree requires secp256k1 recovery keys.
const recoveryKeyUri = yield keyManager.generateKey({ algorithm: DidIonRegisteredKeyType.secp256k1 });
const recoveryKey = yield keyManager.getPublicKey({ keyUri: recoveryKeyUri });
// Generate a random key for the ION Update Key. Sidetree requires secp256k1 update keys.
const updateKeyUri = yield keyManager.generateKey({ algorithm: DidIonRegisteredKeyType.secp256k1 });
const updateKey = yield keyManager.getPublicKey({ keyUri: updateKeyUri });
// Compute the Long Form DID URI from the keys and services, if any.
const longFormDidUri = yield DidIonUtils.computeLongFormDidUri({
recoveryKey,
updateKey,
services: (_f = options.services) !== null && _f !== void 0 ? _f : [],
verificationMethods: verificationMethodsToAdd
});
// Expand the DID URI string to a DID document.
const { didDocument, didResolutionMetadata } = yield DidIon.resolve(longFormDidUri, { gatewayUri: options.gatewayUri });
if (didDocument === null) {
throw new Error(`Unable to resolve DID during creation: ${didResolutionMetadata === null || didResolutionMetadata === void 0 ? void 0 : didResolutionMetadata.error}`);
}
// Create the BearerDid object, including the "Short Form" of the DID URI, the ION update and
// recovery keys, and specifying that the DID has not yet been published.
const did = new BearerDid({
uri: longFormDidUri,
document: didDocument,
metadata: {
published: false,
canonicalId: longFormDidUri.split(':', 3).join(':'),
recoveryKey,
updateKey
},
keyManager
});
// By default, publish the DID document to a Sidetree node unless explicitly disabled.
if ((_g = options.publish) !== null && _g !== void 0 ? _g : true) {
const registrationResult = yield DidIon.publish({ did, gatewayUri: options.gatewayUri });
did.metadata = registrationResult.didDocumentMetadata;
}
return did;
});
}
/**
* Given the W3C DID Document of a `did:ion` DID, return the verification method that will be used
* for signing messages and credentials. If given, the `methodId` parameter is used to select the
* verification method. If not given, the first verification method in the authentication property
* in the DID Document is used.
*
* @param params - The parameters for the `getSigningMethod` operation.
* @param params.didDocument - DID Document to get the verification method from.
* @param params.methodId - ID of the verification method to use for signing.
* @returns Verification method to use for signing.
*/
static getSigningMethod(_a) {
return __awaiter(this, arguments, void 0, function* ({ didDocument, methodId }) {
var _b;
// Verify the DID method is supported.
const parsedDid = Did.parse(didDocument.id);
if (parsedDid && parsedDid.method !== this.methodName) {
throw new DidError(DidErrorCode.MethodNotSupported, `Method not supported: ${parsedDid.method}`);
}
// Get the verification method with either the specified ID or the first assertion method.
const verificationMethod = (_b = didDocument.verificationMethod) === null || _b === void 0 ? void 0 : _b.find(vm => { var _a; return vm.id === (methodId !== null && methodId !== void 0 ? methodId : (_a = didDocument.assertionMethod) === null || _a === void 0 ? void 0 : _a[0]); });
if (!(verificationMethod && verificationMethod.publicKeyJwk)) {
throw new DidError(DidErrorCode.InternalError, 'A verification method intended for signing could not be determined from the DID Document');
}
return verificationMethod;
});
}
/**
* Instantiates a {@link BearerDid} object for the DID ION method from a given {@link PortableDid}.
*
* This method allows for the creation of a `BearerDid` object using a previously created DID's
* key material, DID document, and metadata.
*
* @example
* ```ts
* // Export an existing BearerDid to PortableDid format.
* const portableDid = await did.export();
* // Reconstruct a BearerDid object from the PortableDid.
* const did = await DidIon.import({ portableDid });
* ```
*
* @param params - The parameters for the import operation.
* @param params.portableDid - The PortableDid object to import.
* @param params.keyManager - Optionally specify an external Key Management System (KMS) used to
* generate keys and sign data. If not given, a new
* {@link LocalKeyManager} instance will be created and
* used.
* @returns A Promise resolving to a `BearerDid` object representing the DID formed from the
* provided PortableDid.
* @throws An error if the DID document does not contain any verification methods or the keys for
* any verification method are missing in the key manager.
*/
static import(_a) {
return __awaiter(this, arguments, void 0, function* ({ portableDid, keyManager = new LocalKeyManager() }) {
// Verify the DID method is supported.
const parsedDid = Did.parse(portableDid.uri);
if ((parsedDid === null || parsedDid === void 0 ? void 0 : parsedDid.method) !== DidIon.methodName) {
throw new DidError(DidErrorCode.MethodNotSupported, `Method not supported`);
}
const did = yield BearerDid.import({ portableDid, keyManager });
return did;
});
}
/**
* Publishes a DID to a Sidetree node, making it publicly discoverable and resolvable.
*
* This method handles the publication of a DID Document associated with a `did:ion` DID to a
* Sidetree node.
*
* @remarks
* - This method is typically invoked automatically during the creation of a new DID unless the
* `publish` option is set to `false`.
* - For existing, unpublished DIDs, it can be used to publish the DID Document to a Sidetree node.
* - The method relies on the specified Sidetree node to interface with the network.
*
* @param params - The parameters for the `publish` operation.
* @param params.did - The `BearerDid` object representing the DID to be published.
* @param params.gatewayUri - Optional. The URI of a server involved in executing DID
* method operations. In the context of publishing, the
* endpoint is expected to be a Sidetree node. If not
* specified, a default node is used.
* @returns A Promise resolving to a boolean indicating whether the publication was successful.
*
* @example
* ```ts
* // Generate a new DID and keys but explicitly disable publishing.
* const did = await DidIon.create({ options: { publish: false } });
* // Publish the DID to the Sidetree network.
* const isPublished = await DidIon.publish({ did });
* // `isPublished` is true if the DID was successfully published.
* ```
*/
static publish(_a) {
return __awaiter(this, arguments, void 0, function* ({ did, gatewayUri = DEFAULT_GATEWAY_URI }) {
var _b, _c, _d;
// Construct an ION verification method made up of the id, public key, and purposes from each
// verification method in the DID document.
const verificationMethods = (_c = (_b = did.document.verificationMethod) === null || _b === void 0 ? void 0 : _b.map(vm => ({
id: vm.id,
publicKeyJwk: vm.publicKeyJwk,
purposes: getVerificationRelationshipsById({ didDocument: did.document, methodId: vm.id })
}))) !== null && _c !== void 0 ? _c : [];
// Create the ION document.
const ionDocument = yield DidIonUtils.createIonDocument({
services: (_d = did.document.service) !== null && _d !== void 0 ? _d : [],
verificationMethods
});
// Construct the ION Create Operation request.
const createOperation = yield DidIonUtils.constructCreateRequest({
ionDocument,
recoveryKey: did.metadata.recoveryKey,
updateKey: did.metadata.updateKey
});
try {
// Construct the URL of the SideTree node's operations endpoint.
const operationsUrl = DidIonUtils.appendPathToUrl({
baseUrl: gatewayUri,
path: `/operations`
});
// Submit the Create Operation to the operations endpoint.
const response = yield fetch(operationsUrl, {
method: 'POST',
mode: 'cors',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(createOperation)
});
// Return the result of processing the Create operation, including the updated DID metadata
// with the publishing result.
return {
didDocument: did.document,
didDocumentMetadata: Object.assign(Object.assign({}, did.metadata), { published: response.ok }),
didRegistrationMetadata: {}
};
}
catch (error) {
return {
didDocument: null,
didDocumentMetadata: {
published: false,
},
didRegistrationMetadata: {
error: DidErrorCode.InternalError,
errorMessage: `Failed to publish DID document for: ${did.uri}`
}
};
}
});
}
/**
* Resolves a `did:ion` identifier to its corresponding DID document.
*
* This method performs the resolution of a `did:ion` DID, retrieving its DID Document from the
* Sidetree-based DID overlay network. The process involves querying a Sidetree node to retrieve
* the DID Document that corresponds to the given DID identifier.
*
* @remarks
* - If a `gatewayUri` option is not specified, a default node is used to access the Sidetree
* network.
* - It decodes the DID identifier and retrieves the associated DID Document and metadata.
* - In case of resolution failure, appropriate error information is returned.
*
* @example
* ```ts
* const resolutionResult = await DidIon.resolve('did:ion:example');
* ```
*
* @param didUri - The DID to be resolved.
* @param options - Optional parameters for resolving the DID. Unused by this DID method.
* @returns A Promise resolving to a {@link DidResolutionResult} object representing the result of the resolution.
*/
static resolve(didUri_1) {
return __awaiter(this, arguments, void 0, function* (didUri, options = {}) {
var _a, _b;
// Attempt to parse the DID URI.
const parsedDid = Did.parse(didUri);
// If parsing failed, the DID is invalid.
if (!parsedDid) {
return Object.assign(Object.assign({}, EMPTY_DID_RESOLUTION_RESULT), { didResolutionMetadata: { error: 'invalidDid' } });
}
// If the DID method is not "ion", return an error.
if (parsedDid.method !== DidIon.methodName) {
return Object.assign(Object.assign({}, EMPTY_DID_RESOLUTION_RESULT), { didResolutionMetadata: { error: 'methodNotSupported' } });
}
// To execute the read method operation, use the given gateway URI or a default Sidetree node.
const gatewayUri = (_a = options === null || options === void 0 ? void 0 : options.gatewayUri) !== null && _a !== void 0 ? _a : DEFAULT_GATEWAY_URI;
try {
// Construct the URL to be used in the resolution request.
const resolutionUrl = DidIonUtils.appendPathToUrl({
baseUrl: gatewayUri,
path: `/identifiers/${didUri}`
});
// Attempt to retrieve the DID document and metadata from the Sidetree node.
const response = yield fetch(resolutionUrl);
// If the DID document was not found, return an error.
if (!response.ok) {
throw new DidError(DidErrorCode.NotFound, `Unable to find DID document for: ${didUri}`);
}
// If the DID document was retrieved successfully, return it.
const { didDocument, didDocumentMetadata } = yield response.json();
return Object.assign(Object.assign(Object.assign({}, EMPTY_DID_RESOLUTION_RESULT), didDocument && { didDocument }), { didDocumentMetadata: Object.assign({ published: (_b = didDocumentMetadata === null || didDocumentMetadata === void 0 ? void 0 : didDocumentMetadata.method) === null || _b === void 0 ? void 0 : _b.published }, didDocumentMetadata) });
}
catch (error) {
// Rethrow any unexpected errors that are not a `DidError`.
if (!(error instanceof DidError))
throw new Error(error);
// Return a DID Resolution Result with the appropriate error code.
return Object.assign(Object.assign({}, EMPTY_DID_RESOLUTION_RESULT), { didResolutionMetadata: Object.assign({ error: error.code }, error.message && { errorMessage: error.message }) });
}
});
}
}
/**
* Name of the DID method, as defined in the DID ION specification.
*/
DidIon.methodName = 'ion';
/**
* The `DidIonUtils` class provides utility functions to support operations in the DID ION method.
*/
export class DidIonUtils {
/**
* Appends a specified path to a base URL, ensuring proper formatting of the resulting URL.
*
* This method is useful for constructing URLs for accessing various endpoints, such as Sidetree
* nodes in the ION network. It handles the nuances of URL path concatenation, including the
* addition or removal of leading/trailing slashes, to create a well-formed URL.
*
* @param params - The parameters for URL construction.
* @param params.baseUrl - The base URL to which the path will be appended.
* @param params.path - The path to append to the base URL.
* @returns The fully constructed URL string with the path appended to the base URL.
*/
static appendPathToUrl({ baseUrl, path }) {
const url = new URL(baseUrl);
url.pathname = url.pathname.endsWith('/') ? url.pathname : url.pathname + '/';
url.pathname += path.startsWith('/') ? path.substring(1) : path;
return url.toString();
}
/**
* Computes the Long Form DID URI given an ION DID's recovery key, update key, services, and
* verification methods.
*
* @param params - The parameters for computing the Long Form DID URI.
* @param params.recoveryKey - The ION Recovery Key.
* @param params.updateKey - The ION Update Key.
* @param params.services - An array of services associated with the DID.
* @param params.verificationMethods - An array of verification methods associated with the DID.
* @returns A Promise resolving to the Long Form DID URI.
*/
static computeLongFormDidUri(_a) {
return __awaiter(this, arguments, void 0, function* ({ recoveryKey, updateKey, services, verificationMethods }) {
// Create the ION document.
const ionDocument = yield DidIonUtils.createIonDocument({ services, verificationMethods });
// Normalize JWK to onnly include specific members and in lexicographic order.
const normalizedRecoveryKey = DidIonUtils.normalizeJwk(recoveryKey);
const normalizedUpdateKey = DidIonUtils.normalizeJwk(updateKey);
// Compute the Long Form DID URI.
const longFormDidUri = yield IonDid.createLongFormDid({
document: ionDocument,
recoveryKey: normalizedRecoveryKey,
updateKey: normalizedUpdateKey
});
return longFormDidUri;
});
}
/**
* Constructs a Sidetree Create Operation request for a DID document within the ION network.
*
* This method prepares the necessary payload for submitting a Create Operation to a Sidetree
* node, encapsulating the details of the DID document, recovery key, and update key.
*
* @param params - Parameters required to construct the Create Operation request.
* @param params.ionDocument - The DID document model containing public keys and service endpoints.
* @param params.recoveryKey - The recovery public key in JWK format.
* @param params.updateKey - The update public key in JWK format.
* @returns A promise resolving to the ION Create Operation request model, ready for submission to a Sidetree node.
*/
static constructCreateRequest(_a) {
return __awaiter(this, arguments, void 0, function* ({ ionDocument, recoveryKey, updateKey }) {
// Create an ION DID create request operation.
const createRequest = yield IonRequest.createCreateRequest({
document: ionDocument,
recoveryKey: DidIonUtils.normalizeJwk(recoveryKey),
updateKey: DidIonUtils.normalizeJwk(updateKey)
});
return createRequest;
});
}
/**
* Assembles an ION document model from provided services and verification methods
*
* This model serves as the foundation for a DID document in the ION network, facilitating the
* creation and management of decentralized identities. It translates service endpoints and
* public keys into a format compatible with the Sidetree protocol, ensuring the resulting DID
* document adheres to the required specifications for ION DIDs. This method is essential for
* constructing the payload needed to register or update DIDs within the ION network.
*
* @param params - The parameters containing the services and verification methods to include in the ION document.
* @param params.services - A list of service endpoints to be included in the DID document, specifying ways to interact with the DID subject.
* @param params.verificationMethods - A list of verification methods to be included, detailing the cryptographic keys and their intended uses within the DID document.
* @returns A Promise resolving to an `IonDocumentModel`, ready for use in Sidetree operations like DID creation and updates.
*/
static createIonDocument(_a) {
return __awaiter(this, arguments, void 0, function* ({ services, verificationMethods }) {
var _b, _c;
/**
* STEP 1: Convert verification methods to ION SDK format.
*/
const ionPublicKeys = [];
for (const vm of verificationMethods) {
// Use the given ID, the key's ID, or the key's thumbprint as the verification method ID.
let methodId = (_c = (_b = vm.id) !== null && _b !== void 0 ? _b : vm.publicKeyJwk.kid) !== null && _c !== void 0 ? _c : yield computeJwkThumbprint({ jwk: vm.publicKeyJwk });
methodId = `${methodId.split('#').pop()}`; // Remove fragment prefix, if any.
// Convert public key JWK to ION format.
const publicKey = {
id: methodId,
publicKeyJwk: DidIonUtils.normalizeJwk(vm.publicKeyJwk),
purposes: vm.purposes,
type: 'JsonWebKey2020'
};
ionPublicKeys.push(publicKey);
}
/**
* STEP 2: Convert service entries, if any, to ION SDK format.
*/
const ionServices = services.map(service => (Object.assign(Object.assign({}, service), { id: `${service.id.split('#').pop()}` // Remove fragment prefix, if any.
})));
/**
* STEP 3: Format as ION document.
*/
const ionDocumentModel = {
publicKeys: ionPublicKeys,
services: ionServices
};
return ionDocumentModel;
});
}
/**
* Normalize the given JWK to include only specific members and in lexicographic order.
*
* @param jwk - The JWK to normalize.
* @returns The normalized JWK.
*/
static normalizeJwk(jwk) {
const keyType = jwk.kty;
let normalizedJwk;
if (keyType === 'EC') {
normalizedJwk = { crv: jwk.crv, kty: jwk.kty, x: jwk.x, y: jwk.y };
}
else if (keyType === 'oct') {
normalizedJwk = { k: jwk.k, kty: jwk.kty };
}
else if (keyType === 'OKP') {
normalizedJwk = { crv: jwk.crv, kty: jwk.kty, x: jwk.x };
}
else if (keyType === 'RSA') {
normalizedJwk = { e: jwk.e, kty: jwk.kty, n: jwk.n };
}
else {
throw new Error(`Unsupported key type: ${keyType}`);
}
return normalizedJwk;
}
}
//# sourceMappingURL=did-ion.js.map
File diff suppressed because one or more lines are too long
+298
View File
@@ -0,0 +1,298 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Convert } from '@web5/common';
import { LocalKeyManager } from '@web5/crypto';
import { Did } from '../did.js';
import { DidMethod } from './did-method.js';
import { BearerDid } from '../bearer-did.js';
import { DidError, DidErrorCode } from '../did-error.js';
import { EMPTY_DID_RESOLUTION_RESULT } from '../types/did-resolution.js';
/**
* The `DidJwk` class provides an implementation of the `did:jwk` DID method.
*
* Features:
* - DID Creation: Create new `did:jwk` DIDs.
* - DID Key Management: Instantiate a DID object from an existing verification method key set or
* or a key in a Key Management System (KMS). If supported by the KMS, a DID's
* key can be exported to a portable DID format.
* - DID Resolution: Resolve a `did:jwk` to its corresponding DID Document.
* - Signature Operations: Sign and verify messages using keys associated with a DID.
*
* @remarks
* The `did:jwk` DID method uses a single JSON Web Key (JWK) to generate a DID and does not rely
* on any external system such as a blockchain or centralized database. This characteristic makes
* it suitable for use cases where a assertions about a DID Subject can be self-verifiable by
* third parties.
*
* The DID URI is formed by Base64URL-encoding the JWK and prefixing with `did:jwk:`. The DID
* Document of a `did:jwk` DID contains a single verification method, which is the JWK used
* to generate the DID. The verification method is identified by the key ID `#0`.
*
* @see {@link https://github.com/quartzjer/did-jwk/blob/main/spec.md | DID JWK Specification}
*
* @example
* ```ts
* // DID Creation
* const did = await DidJwk.create();
*
* // DID Creation with a KMS
* const keyManager = new LocalKeyManager();
* const did = await DidJwk.create({ keyManager });
*
* // DID Resolution
* const resolutionResult = await DidJwk.resolve({ did: did.uri });
*
* // Signature Operations
* const signer = await did.getSigner();
* const signature = await signer.sign({ data: new TextEncoder().encode('Message') });
* const isValid = await signer.verify({ data: new TextEncoder().encode('Message'), signature });
*
* // Key Management
*
* // Instantiate a DID object from an existing key in a KMS
* const did = await DidJwk.fromKeyManager({
* didUri: 'did:jwk:eyJrIjoiT0tQIiwidCI6IkV1c2UyNTYifQ',
* keyManager
* });
*
* // Instantiate a DID object from an existing verification method key
* const did = await DidJwk.fromKeys({
* verificationMethods: [{
* publicKeyJwk: {
* kty: 'OKP',
* crv: 'Ed25519',
* x: 'cHs7YMLQ3gCWjkacMURBsnEJBcEsvlsE5DfnsfTNDP4'
* },
* privateKeyJwk: {
* kty: 'OKP',
* crv: 'Ed25519',
* x: 'cHs7YMLQ3gCWjkacMURBsnEJBcEsvlsE5DfnsfTNDP4',
* d: 'bdcGE4KzEaekOwoa-ee3gAm1a991WvNj_Eq3WKyqTnE'
* }
* }]
* });
*
* // Convert a DID object to a portable format
* const portableDid = await DidJwk.toKeys({ did });
*
* // Reconstruct a DID object from a portable format
* const did = await DidJwk.fromKeys(portableDid);
* ```
*/
export class DidJwk extends DidMethod {
/**
* Creates a new DID using the `did:jwk` method formed from a newly generated key.
*
* @remarks
* The DID URI is formed by Base64URL-encoding the JWK and prefixing with `did:jwk:`.
*
* Notes:
* - If no `options` are given, by default a new Ed25519 key will be generated.
* - The `algorithm` and `verificationMethods` options are mutually exclusive. If both are given,
* an error will be thrown.
*
* @example
* ```ts
* // DID Creation
* const did = await DidJwk.create();
*
* // DID Creation with a KMS
* const keyManager = new LocalKeyManager();
* const did = await DidJwk.create({ keyManager });
* ```
*
* @param params - The parameters for the create operation.
* @param params.keyManager - Optionally specify a Key Management System (KMS) used to generate
* keys and sign data.
* @param params.options - Optional parameters that can be specified when creating a new DID.
* @returns A Promise resolving to a {@link BearerDid} object representing the new DID.
*/
static create() {
return __awaiter(this, arguments, void 0, function* ({ keyManager = new LocalKeyManager(), options = {} } = {}) {
// Before processing the create operation, validate DID-method-specific requirements to prevent
// keys from being generated unnecessarily.
var _a, _b, _c, _d;
// Check 1: Validate that `algorithm` or `verificationMethods` options are not both given.
if (options.algorithm && options.verificationMethods) {
throw new Error(`The 'algorithm' and 'verificationMethods' options are mutually exclusive`);
}
// Check 2: If `verificationMethods` is given, it must contain exactly one entry since DID JWK
// only supports a single verification method.
if (options.verificationMethods && options.verificationMethods.length !== 1) {
throw new Error(`The 'verificationMethods' option must contain exactly one entry`);
}
// Default to Ed25519 key generation if an algorithm is not given.
const algorithm = (_d = (_a = options.algorithm) !== null && _a !== void 0 ? _a : (_c = (_b = options.verificationMethods) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.algorithm) !== null && _d !== void 0 ? _d : 'Ed25519';
// Generate a new key using the specified `algorithm`.
const keyUri = yield keyManager.generateKey({ algorithm });
const publicKey = yield keyManager.getPublicKey({ keyUri });
// Compute the DID identifier from the public key by serializing the JWK to a UTF-8 string and
// encoding in Base64URL format.
const identifier = Convert.object(publicKey).toBase64Url();
// Attach the prefix `did:jwk` to form the complete DID URI.
const didUri = `did:${DidJwk.methodName}:${identifier}`;
// Expand the DID URI string to a DID document.
const didResolutionResult = yield DidJwk.resolve(didUri);
const document = didResolutionResult.didDocument;
// Create the BearerDid object from the generated key material.
const did = new BearerDid({
uri: didUri,
document,
metadata: {},
keyManager
});
return did;
});
}
/**
* Given the W3C DID Document of a `did:jwk` DID, return the verification method that will be used
* for signing messages and credentials. If given, the `methodId` parameter is used to select the
* verification method. If not given, the first verification method in the DID Document is used.
*
* Note that for DID JWK, only one verification method can exist so specifying `methodId` could be
* considered redundant or unnecessary. The option is provided for consistency with other DID
* method implementations.
*
* @param params - The parameters for the `getSigningMethod` operation.
* @param params.didDocument - DID Document to get the verification method from.
* @param params.methodId - ID of the verification method to use for signing.
* @returns Verification method to use for signing.
*/
static getSigningMethod(_a) {
return __awaiter(this, arguments, void 0, function* ({ didDocument }) {
var _b;
// Verify the DID method is supported.
const parsedDid = Did.parse(didDocument.id);
if (parsedDid && parsedDid.method !== this.methodName) {
throw new DidError(DidErrorCode.MethodNotSupported, `Method not supported: ${parsedDid.method}`);
}
// Attempt to find the verification method in the DID Document.
const [verificationMethod] = (_b = didDocument.verificationMethod) !== null && _b !== void 0 ? _b : [];
if (!(verificationMethod && verificationMethod.publicKeyJwk)) {
throw new DidError(DidErrorCode.InternalError, 'A verification method intended for signing could not be determined from the DID Document');
}
return verificationMethod;
});
}
/**
* Instantiates a {@link BearerDid} object for the DID JWK method from a given {@link PortableDid}.
*
* This method allows for the creation of a `BearerDid` object using a previously created DID's
* key material, DID document, and metadata.
*
* @remarks
* The `verificationMethod` array of the DID document must contain exactly one key since the
* `did:jwk` method only supports a single verification method.
*
* @example
* ```ts
* // Export an existing BearerDid to PortableDid format.
* const portableDid = await did.export();
* // Reconstruct a BearerDid object from the PortableDid.
* const did = await DidJwk.import({ portableDid });
* ```
*
* @param params - The parameters for the import operation.
* @param params.portableDid - The PortableDid object to import.
* @param params.keyManager - Optionally specify an external Key Management System (KMS) used to
* generate keys and sign data. If not given, a new
* {@link LocalKeyManager} instance will be created and
* used.
* @returns A Promise resolving to a `BearerDid` object representing the DID formed from the provided keys.
* @throws An error if the DID document does not contain exactly one verification method.
*/
static import(_a) {
return __awaiter(this, arguments, void 0, function* ({ portableDid, keyManager = new LocalKeyManager() }) {
// Verify the DID method is supported.
const parsedDid = Did.parse(portableDid.uri);
if ((parsedDid === null || parsedDid === void 0 ? void 0 : parsedDid.method) !== DidJwk.methodName) {
throw new DidError(DidErrorCode.MethodNotSupported, `Method not supported`);
}
// Use the given PortableDid to construct the BearerDid object.
const did = yield BearerDid.import({ portableDid, keyManager });
// Validate that the given DID document contains exactly one verification method.
// Note: The non-undefined assertion is necessary because the type system cannot infer that
// the `verificationMethod` property is defined -- which is checked by `BearerDid.import()`.
if (did.document.verificationMethod.length !== 1) {
throw new DidError(DidErrorCode.InvalidDidDocument, `DID document must contain exactly one verification method`);
}
return did;
});
}
/**
* Resolves a `did:jwk` identifier to a DID Document.
*
* @param didUri - The DID to be resolved.
* @param _options - Optional parameters for resolving the DID. Unused by this DID method.
* @returns A Promise resolving to a {@link DidResolutionResult} object representing the result of the resolution.
*/
static resolve(didUri, _options) {
return __awaiter(this, void 0, void 0, function* () {
// Attempt to parse the DID URI.
const parsedDid = Did.parse(didUri);
// Attempt to decode the Base64URL-encoded JWK.
let publicKey;
try {
publicKey = Convert.base64Url(parsedDid.id).toObject();
}
catch ( /* Consume the error so that a DID resolution error can be returned later. */_a) { /* Consume the error so that a DID resolution error can be returned later. */ }
// If parsing or decoding failed, the DID is invalid.
if (!parsedDid || !publicKey) {
return Object.assign(Object.assign({}, EMPTY_DID_RESOLUTION_RESULT), { didResolutionMetadata: { error: 'invalidDid' } });
}
// If the DID method is not "jwk", return an error.
if (parsedDid.method !== DidJwk.methodName) {
return Object.assign(Object.assign({}, EMPTY_DID_RESOLUTION_RESULT), { didResolutionMetadata: { error: 'methodNotSupported' } });
}
const didDocument = {
'@context': [
'https://www.w3.org/ns/did/v1'
],
id: parsedDid.uri
};
const keyUri = `${didDocument.id}#0`;
// Set the Verification Method property.
didDocument.verificationMethod = [{
id: keyUri,
type: 'JsonWebKey',
controller: didDocument.id,
publicKeyJwk: publicKey
}];
// Set the Verification Relationship properties.
didDocument.authentication = [keyUri];
didDocument.assertionMethod = [keyUri];
didDocument.capabilityInvocation = [keyUri];
didDocument.capabilityDelegation = [keyUri];
didDocument.keyAgreement = [keyUri];
// If the JWK contains a `use` property with the value "sig" then the `keyAgreement` property
// is not included in the DID Document. If the `use` value is "enc" then only the `keyAgreement`
// property is included in the DID Document.
switch (publicKey.use) {
case 'sig': {
delete didDocument.keyAgreement;
break;
}
case 'enc': {
delete didDocument.authentication;
delete didDocument.assertionMethod;
delete didDocument.capabilityInvocation;
delete didDocument.capabilityDelegation;
break;
}
}
return Object.assign(Object.assign({}, EMPTY_DID_RESOLUTION_RESULT), { didDocument });
});
}
}
/**
* Name of the DID method, as defined in the DID JWK specification.
*/
DidJwk.methodName = 'jwk';
//# sourceMappingURL=did-jwk.js.map
@@ -0,0 +1 @@
{"version":3,"file":"did-jwk.js","sourceRoot":"","sources":["../../../src/methods/did-jwk.ts"],"names":[],"mappings":"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"}
+983
View File
@@ -0,0 +1,983 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Multicodec, universalTypeOf } from '@web5/common';
import { X25519, Ed25519, Secp256k1, Secp256r1, LocalKeyManager, } from '@web5/crypto';
import { Did } from '../did.js';
import { DidMethod } from './did-method.js';
import { BearerDid } from '../bearer-did.js';
import { DidError, DidErrorCode } from '../did-error.js';
import { EMPTY_DID_RESOLUTION_RESULT } from '../types/did-resolution.js';
import { getVerificationMethodTypes, keyBytesToMultibaseId, multibaseIdToKeyBytes } from '../utils.js';
/**
* Enumerates the types of keys that can be used in a DID Key document.
*
* The DID Key method supports various cryptographic key types. These key types are essential for
* the creation and management of DIDs and their associated cryptographic operations like signing
* and encryption.
*/
export var DidKeyRegisteredKeyType;
(function (DidKeyRegisteredKeyType) {
/**
* Ed25519: A public-key signature system using the EdDSA (Edwards-curve Digital Signature
* Algorithm) and Curve25519.
*/
DidKeyRegisteredKeyType["Ed25519"] = "Ed25519";
/**
* secp256k1: A cryptographic curve used for digital signatures in a range of decentralized
* systems.
*/
DidKeyRegisteredKeyType["secp256k1"] = "secp256k1";
/**
* secp256r1: Also known as P-256 or prime256v1, this curve is used for cryptographic operations
* and is widely supported in various cryptographic libraries and standards.
*/
DidKeyRegisteredKeyType["secp256r1"] = "secp256r1";
/**
* X25519: A Diffie-Hellman key exchange algorithm using Curve25519.
*/
DidKeyRegisteredKeyType["X25519"] = "X25519";
})(DidKeyRegisteredKeyType || (DidKeyRegisteredKeyType = {}));
/**
* Enumerates the verification method types supported by the DID Key method.
*
* This enum defines the URIs associated with common verification methods used in DID Documents.
* These URIs represent cryptographic suites or key types standardized for use across decentralized
* identifiers (DIDs).
*/
export const DidKeyVerificationMethodType = {
/** Represents an Ed25519 public key used for digital signatures. */
Ed25519VerificationKey2020: 'https://w3id.org/security/suites/ed25519-2020/v1',
/** Represents a JSON Web Key (JWK) used for digital signatures and key agreement protocols. */
JsonWebKey2020: 'https://w3id.org/security/suites/jws-2020/v1',
/** Represents an X25519 public key used for key agreement protocols. */
X25519KeyAgreementKey2020: 'https://w3id.org/security/suites/x25519-2020/v1',
};
/**
* Private helper that maps algorithm identifiers to their corresponding DID Key
* {@link DidKeyRegisteredKeyType | registered key type}.
*/
const AlgorithmToKeyTypeMap = {
Ed25519: DidKeyRegisteredKeyType.Ed25519,
ES256K: DidKeyRegisteredKeyType.secp256k1,
ES256: DidKeyRegisteredKeyType.secp256r1,
'P-256': DidKeyRegisteredKeyType.secp256r1,
secp256k1: DidKeyRegisteredKeyType.secp256k1,
secp256r1: DidKeyRegisteredKeyType.secp256r1,
X25519: DidKeyRegisteredKeyType.X25519
};
/**
* The `DidKey` class provides an implementation of the 'did:key' DID method.
*
* Features:
* - DID Creation: Create new `did:key` DIDs.
* - DID Key Management: Instantiate a DID object from an existing verification method key set or
* or a key in a Key Management System (KMS). If supported by the KMS, a DID's
* key can be exported to a portable DID format.
* - DID Resolution: Resolve a `did:key` to its corresponding DID Document.
* - Signature Operations: Sign and verify messages using keys associated with a DID.
*
* @remarks
* The `did:key` DID method uses a single public key to generate a DID and does not rely
* on any external system such as a blockchain or centralized database. This characteristic makes
* it suitable for use cases where a assertions about a DID Subject can be self-verifiable by
* third parties.
*
* The method-specific identifier is formed by
* {@link https://datatracker.ietf.org/doc/html/draft-multiformats-multibase#name-base-58-bitcoin-encoding | Multibase base58-btc}
* encoding the concatenation of the
* {@link https://github.com/multiformats/multicodec/blob/master/README.md | Multicodec} identifier
* for the public key type and the raw public key bytes. To form the DID URI, the method-specific
* identifier is prefixed with the string 'did:key:'.
*
* This method can optionally derive an encryption key from the public key used to create the DID
* if and only if the public key algorithm is `Ed25519`. This feature enables the same DID to be
* used for encrypted communication, in addition to signature verification. To enable this
* feature when calling {@link DidKey.create | `DidKey.create()`}, first specify an `algorithm` of
* `Ed25519` or provide a `keySet` referencing an `Ed25519` key and then set the
* `enableEncryptionKeyDerivation` option to `true`.
*
* Note:
* - The authors of the DID Key specification have indicated that use of this method for long-lived
* use cases is only recommended when accompanied with high confidence that private keys are
* securely protected by software or hardware isolation.
*
* @see {@link https://w3c-ccg.github.io/did-method-key/ | DID Key Specification}
*
* @example
* ```ts
* // DID Creation
* const did = await DidKey.create();
*
* // DID Creation with a KMS
* const keyManager = new LocalKeyManager();
* const did = await DidKey.create({ keyManager });
*
* // DID Resolution
* const resolutionResult = await DidKey.resolve({ did: did.uri });
*
* // Signature Operations
* const signer = await did.getSigner();
* const signature = await signer.sign({ data: new TextEncoder().encode('Message') });
* const isValid = await signer.verify({ data: new TextEncoder().encode('Message'), signature });
*
* // Key Management
*
* // Instantiate a DID object from an existing key in a KMS
* const did = await DidKey.fromKeyManager({
* didUri: 'did:key:z6MkpUzNmYVTGpqhStxK8yRKXWCRNm1bGYz8geAg2zmjYHKX',
* keyManager
* });
*
* // Instantiate a DID object from an existing verification method key
* const did = await DidKey.fromKeys({
* verificationMethods: [{
* publicKeyJwk: {
* kty: 'OKP',
* crv: 'Ed25519',
* x: 'cHs7YMLQ3gCWjkacMURBsnEJBcEsvlsE5DfnsfTNDP4'
* },
* privateKeyJwk: {
* kty: 'OKP',
* crv: 'Ed25519',
* x: 'cHs7YMLQ3gCWjkacMURBsnEJBcEsvlsE5DfnsfTNDP4',
* d: 'bdcGE4KzEaekOwoa-ee3gAm1a991WvNj_Eq3WKyqTnE'
* }
* }]
* });
*
* // Convert a DID object to a portable format
* const portableDid = await DidKey.toKeys({ did });
*
* // Reconstruct a DID object from a portable format
* const did = await DidKey.fromKeys(portableDid);
* ```
*/
export class DidKey extends DidMethod {
/**
* Creates a new DID using the `did:key` method formed from a newly generated key.
*
* @remarks
* The DID URI is formed by
* {@link https://datatracker.ietf.org/doc/html/draft-multiformats-multibase#name-base-58-bitcoin-encoding | Multibase base58-btc}
* encoding the
* {@link https://github.com/multiformats/multicodec/blob/master/README.md | Multicodec}-encoded
* public key and prefixing with `did:key:`.
*
* This method can optionally derive an encryption key from the public key used to create the DID
* if and only if the public key algorithm is `Ed25519`. This feature enables the same DID to be
* used for encrypted communication, in addition to signature verification. To enable this
* feature, specify an `algorithm` of `Ed25519` as either a top-level option or in a
* `verificationMethod` and set the `enableEncryptionKeyDerivation` option to `true`.
*
* Notes:
* - If no `options` are given, by default a new Ed25519 key will be generated.
* - The `algorithm` and `verificationMethods` options are mutually exclusive. If both are given,
* an error will be thrown.
*
* @example
* ```ts
* // DID Creation
* const did = await DidKey.create();
*
* // DID Creation with a KMS
* const keyManager = new LocalKeyManager();
* const did = await DidKey.create({ keyManager });
* ```
*
* @param params - The parameters for the create operation.
* @param params.keyManager - Key Management System (KMS) used to generate keys and sign data.
* @param params.options - Optional parameters that can be specified when creating a new DID.
* @returns A Promise resolving to a {@link BearerDid} object representing the new DID.
*/
static create() {
return __awaiter(this, arguments, void 0, function* ({ keyManager = new LocalKeyManager(), options = {} } = {}) {
// Before processing the create operation, validate DID-method-specific requirements to prevent
// keys from being generated unnecessarily.
var _a, _b, _c, _d;
// Check 1: Validate that `algorithm` or `verificationMethods` options are not both given.
if (options.algorithm && options.verificationMethods) {
throw new Error(`The 'algorithm' and 'verificationMethods' options are mutually exclusive`);
}
// Check 2: If `verificationMethods` is given, it must contain exactly one entry since DID Key
// only supports a single verification method.
if (options.verificationMethods && options.verificationMethods.length !== 1) {
throw new Error(`The 'verificationMethods' option must contain exactly one entry`);
}
// Default to Ed25519 key generation if an algorithm is not given.
const algorithm = (_d = (_a = options.algorithm) !== null && _a !== void 0 ? _a : (_c = (_b = options.verificationMethods) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.algorithm) !== null && _d !== void 0 ? _d : 'Ed25519';
// Generate a new key using the specified `algorithm`.
const keyUri = yield keyManager.generateKey({ algorithm });
const publicKey = yield keyManager.getPublicKey({ keyUri });
// Compute the DID identifier from the public key by converting the JWK to a multibase-encoded
// multicodec value.
const identifier = yield DidKeyUtils.publicKeyToMultibaseId({ publicKey });
// Attach the prefix `did:key` to form the complete DID URI.
const didUri = `did:${DidKey.methodName}:${identifier}`;
// Expand the DID URI string to a DID document.
const didResolutionResult = yield DidKey.resolve(didUri, options);
const document = didResolutionResult.didDocument;
// Create the BearerDid object from the generated key material.
const did = new BearerDid({
uri: didUri,
document,
metadata: {},
keyManager
});
return did;
});
}
/**
* Given the W3C DID Document of a `did:key` DID, return the verification method that will be used
* for signing messages and credentials. With DID Key, the first verification method in the
* authentication property in the DID Document is used.
*
* Note that for DID Key, only one verification method intended for signing can exist so
* specifying `methodId` could be considered redundant or unnecessary. The option is provided for
* consistency with other DID method implementations.
*
* @param params - The parameters for the `getSigningMethod` operation.
* @param params.didDocument - DID Document to get the verification method from.
* @param params.methodId - ID of the verification method to use for signing.
* @returns Verification method to use for signing.
*/
static getSigningMethod(_a) {
return __awaiter(this, arguments, void 0, function* ({ didDocument }) {
var _b;
// Verify the DID method is supported.
const parsedDid = Did.parse(didDocument.id);
if (parsedDid && parsedDid.method !== this.methodName) {
throw new DidError(DidErrorCode.MethodNotSupported, `Method not supported: ${parsedDid.method}`);
}
// Attempt to ge the first verification method intended for signing claims.
const [methodId] = didDocument.assertionMethod || [];
const verificationMethod = (_b = didDocument.verificationMethod) === null || _b === void 0 ? void 0 : _b.find(vm => vm.id === methodId);
if (!(verificationMethod && verificationMethod.publicKeyJwk)) {
throw new DidError(DidErrorCode.InternalError, 'A verification method intended for signing could not be determined from the DID Document');
}
return verificationMethod;
});
}
/**
* Instantiates a {@link BearerDid} object for the DID Key method from a given {@link PortableDid}.
*
* This method allows for the creation of a `BearerDid` object using a previously created DID's
* key material, DID document, and metadata.
*
* @remarks
* The `verificationMethod` array of the DID document must contain exactly one key since the
* `did:key` method only supports a single verification method.
*
* @example
* ```ts
* // Export an existing BearerDid to PortableDid format.
* const portableDid = await did.export();
* // Reconstruct a BearerDid object from the PortableDid.
* const did = await DidKey.import({ portableDid });
* ```
*
* @param params - The parameters for the import operation.
* @param params.portableDid - The PortableDid object to import.
* @param params.keyManager - Optionally specify an external Key Management System (KMS) used to
* generate keys and sign data. If not given, a new
* {@link LocalKeyManager} instance will be created and
* used.
* @returns A Promise resolving to a `BearerDid` object representing the DID formed from the provided keys.
* @throws An error if the DID document does not contain exactly one verification method.
*/
static import(_a) {
return __awaiter(this, arguments, void 0, function* ({ portableDid, keyManager = new LocalKeyManager() }) {
// Verify the DID method is supported.
const parsedDid = Did.parse(portableDid.uri);
if ((parsedDid === null || parsedDid === void 0 ? void 0 : parsedDid.method) !== DidKey.methodName) {
throw new DidError(DidErrorCode.MethodNotSupported, `Method not supported`);
}
// Use the given PortableDid to construct the BearerDid object.
const did = yield BearerDid.import({ portableDid, keyManager });
// Validate that the given DID document contains exactly one verification method.
// Note: The non-undefined assertion is necessary because the type system cannot infer that
// the `verificationMethod` property is defined -- which is checked by `BearerDid.import()`.
if (did.document.verificationMethod.length !== 1) {
throw new DidError(DidErrorCode.InvalidDidDocument, `DID document must contain exactly one verification method`);
}
return did;
});
}
/**
* Resolves a `did:key` identifier to a DID Document.
*
* @param didUri - The DID to be resolved.
* @param options - Optional parameters for resolving the DID.
* @returns A Promise resolving to a {@link DidResolutionResult} object representing the result of the resolution.
*/
static resolve(didUri, options) {
return __awaiter(this, void 0, void 0, function* () {
try {
// Attempt to expand the DID URI string to a DID document.
const didDocument = yield DidKey.createDocument({ didUri, options });
// If the DID document was created successfully, return it.
return Object.assign(Object.assign({}, EMPTY_DID_RESOLUTION_RESULT), { didDocument });
}
catch (error) {
// Rethrow any unexpected errors that are not a `DidError`.
if (!(error instanceof DidError))
throw new Error(error);
// Return a DID Resolution Result with the appropriate error code.
return Object.assign(Object.assign({}, EMPTY_DID_RESOLUTION_RESULT), { didResolutionMetadata: Object.assign({ error: error.code }, error.message && { errorMessage: error.message }) });
}
});
}
/**
* Expands a did:key identifier to a DID Document.
*
* Reference: https://w3c-ccg.github.io/did-method-key/#document-creation-algorithm
*
* @param options
* @returns - A DID dodcument.
*/
static createDocument(_a) {
return __awaiter(this, arguments, void 0, function* ({ didUri, options = {} }) {
const { defaultContext = 'https://www.w3.org/ns/did/v1', enableEncryptionKeyDerivation = false, enableExperimentalPublicKeyTypes = false, publicKeyFormat = 'JsonWebKey2020' } = options;
/**
* 1. Initialize document to an empty object.
*/
const didDocument = { id: '' };
/**
* 2. Using a colon (:) as the delimiter, split the identifier into its
* components: a scheme, a method, a version, and a multibaseValue.
* If there are only three components set the version to the string
* value 1 and use the last value as the multibaseValue.
*/
const parsedDid = Did.parse(didUri);
if (!parsedDid) {
throw new DidError(DidErrorCode.InvalidDid, `Invalid DID URI: ${didUri}`);
}
const multibaseValue = parsedDid.id;
/**
* 3. Check the validity of the input identifier.
* The scheme MUST be the value did. The method MUST be the value key.
* The version MUST be convertible to a positive integer value. The
* multibaseValue MUST be a string and begin with the letter z. If any
* of these requirements fail, an invalidDid error MUST be raised.
*/
if (parsedDid.method !== DidKey.methodName) {
throw new DidError(DidErrorCode.MethodNotSupported, `Method not supported: ${parsedDid.method}`);
}
if (!DidKey.validateIdentifier(parsedDid)) {
throw new DidError(DidErrorCode.InvalidDid, `Invalid DID URI: ${didUri}`);
}
/**
* 4. Initialize the signatureVerificationMethod to the result of passing
* identifier, multibaseValue, and options to a
* {@link https://w3c-ccg.github.io/did-method-key/#signature-method-creation-algorithm | Signature Method Creation Algorithm}.
*/
const signatureVerificationMethod = yield DidKey.createSignatureMethod({
didUri,
multibaseValue,
options: { enableExperimentalPublicKeyTypes, publicKeyFormat }
});
/**
* 5. Set document.id to identifier. If document.id is not a valid DID,
* an invalidDid error MUST be raised.
*
* Note: Identifier was already confirmed to be valid in Step 3, so
* skipping the redundant validation.
*/
didDocument.id = parsedDid.uri;
/**
* 6. Initialize the verificationMethod property in document to an array
* where the first value is the signatureVerificationMethod.
*/
didDocument.verificationMethod = [signatureVerificationMethod];
/**
* 7. Initialize the authentication, assertionMethod, capabilityInvocation,
* and the capabilityDelegation properties in document to an array where
* the first item is the value of the id property in
* signatureVerificationMethod.
*/
didDocument.authentication = [signatureVerificationMethod.id];
didDocument.assertionMethod = [signatureVerificationMethod.id];
didDocument.capabilityInvocation = [signatureVerificationMethod.id];
didDocument.capabilityDelegation = [signatureVerificationMethod.id];
/**
* 8. If options.enableEncryptionKeyDerivation is set to true:
* Add the encryptionVerificationMethod value to the verificationMethod
* array. Initialize the keyAgreement property in document to an array
* where the first item is the value of the id property in
* encryptionVerificationMethod.
*/
if (enableEncryptionKeyDerivation === true) {
/**
* Although not covered by the did:key method specification, a sensible
* default will be taken to use the 'X25519KeyAgreementKey2020'
* verification method type if the given publicKeyFormat is
* 'Ed25519VerificationKey2020' and 'JsonWebKey2020' otherwise.
*/
const encryptionPublicKeyFormat = (publicKeyFormat === 'Ed25519VerificationKey2020')
? 'X25519KeyAgreementKey2020'
: 'JsonWebKey2020';
/**
* 8.1 Initialize the encryptionVerificationMethod to the result of
* passing identifier, multibaseValue, and options to an
* {@link https://w3c-ccg.github.io/did-method-key/#encryption-method-creation-algorithm | Encryption Method Creation Algorithm}.
*/
const encryptionVerificationMethod = yield this.createEncryptionMethod({
didUri,
multibaseValue,
options: { enableExperimentalPublicKeyTypes, publicKeyFormat: encryptionPublicKeyFormat }
});
/**
* 8.2 Add the encryptionVerificationMethod value to the
* verificationMethod array.
*/
didDocument.verificationMethod.push(encryptionVerificationMethod);
/**
* 8.3. Initialize the keyAgreement property in document to an array
* where the first item is the value of the id property in
* encryptionVerificationMethod.
*/
didDocument.keyAgreement = [encryptionVerificationMethod.id];
}
/**
* 9. Initialize the @context property in document to the result of passing document and options to the Context
* Creation algorithm.
*/
// Set contextArray to an array that is initialized to options.defaultContext.
const contextArray = [defaultContext];
// For every object in every verification relationship listed in document,
// add a string value to the contextArray based on the object type value,
// if it doesn't already exist, according to the following table:
// {@link https://w3c-ccg.github.io/did-method-key/#context-creation-algorithm | Context Type URL}
const verificationMethodTypes = getVerificationMethodTypes({ didDocument });
verificationMethodTypes.forEach((typeName) => {
const typeUrl = DidKeyVerificationMethodType[typeName];
contextArray.push(typeUrl);
});
didDocument['@context'] = contextArray;
/**
* 10. Return document.
*/
return didDocument;
});
}
/**
* Decoding a multibase-encoded multicodec value into a verification method
* that is suitable for verifying that encrypted information will be
* received by the intended recipient.
*/
static createEncryptionMethod(_a) {
return __awaiter(this, arguments, void 0, function* ({ didUri, multibaseValue, options }) {
const { enableExperimentalPublicKeyTypes, publicKeyFormat } = options;
/**
* 1. Initialize verificationMethod to an empty object.
*/
const verificationMethod = { id: '', type: '', controller: '' };
/**
* 2. Set multicodecValue and raw publicKeyBytes to the result of passing multibaseValue and
* options to a Derive Encryption Key algorithm.
*/
const { keyBytes: publicKeyBytes, multicodecCode: multicodecValue, } = yield DidKey.deriveEncryptionKey({ multibaseValue });
/**
* 3. Ensure the proper key length of raw publicKeyBytes based on the multicodecValue table
* provided below:
*
* Multicodec hexadecimal value: 0xec
*
* If the byte length of raw publicKeyBytes does not match the expected public key length for
* the associated multicodecValue, an invalidPublicKeyLength error MUST be raised.
*/
const actualLength = publicKeyBytes.byteLength;
const expectedLength = DidKeyUtils.MULTICODEC_PUBLIC_KEY_LENGTH[multicodecValue];
if (actualLength !== expectedLength) {
throw new DidError(DidErrorCode.InvalidPublicKeyLength, `Expected ${actualLength} bytes. Actual: ${expectedLength}`);
}
/**
* 4. Create the multibaseValue by concatenating the letter 'z' and the
* base58-btc encoding of the concatenation of the multicodecValue and
* the raw publicKeyBytes.
*/
const kemMultibaseValue = keyBytesToMultibaseId({
keyBytes: publicKeyBytes,
multicodecCode: multicodecValue
});
/**
* 5. Set the verificationMethod.id value by concatenating identifier,
* a hash character (#), and the multibaseValue. If verificationMethod.id
* is not a valid DID URL, an invalidDidUrl error MUST be raised.
*/
verificationMethod.id = `${didUri}#${kemMultibaseValue}`;
try {
new URL(verificationMethod.id);
}
catch (error) {
throw new DidError(DidErrorCode.InvalidDidUrl, 'Verification Method ID is not a valid DID URL.');
}
/**
* 6. Set the publicKeyFormat value to the options.publicKeyFormat value.
* 7. If publicKeyFormat is not known to the implementation, an
* unsupportedPublicKeyType error MUST be raised.
*/
if (!(publicKeyFormat in DidKeyVerificationMethodType)) {
throw new DidError(DidErrorCode.UnsupportedPublicKeyType, `Unsupported format: ${publicKeyFormat}`);
}
/**
* 8. If options.enableExperimentalPublicKeyTypes is set to false and publicKeyFormat is not
* Multikey, JsonWebKey2020, or X25519KeyAgreementKey2020, an invalidPublicKeyType error MUST be
* raised.
*/
const StandardPublicKeyTypes = ['Multikey', 'JsonWebKey2020', 'X25519KeyAgreementKey2020'];
if (enableExperimentalPublicKeyTypes === false
&& !(StandardPublicKeyTypes.includes(publicKeyFormat))) {
throw new DidError(DidErrorCode.InvalidPublicKeyType, `Specified '${publicKeyFormat}' without setting enableExperimentalPublicKeyTypes to true.`);
}
/**
* 9. Set verificationMethod.type to the publicKeyFormat value.
*/
verificationMethod.type = publicKeyFormat;
/**
* 10. Set verificationMethod.controller to the identifier value.
*/
verificationMethod.controller = didUri;
/**
* 11. If publicKeyFormat is Multikey or X25519KeyAgreementKey2020, set the verificationMethod.publicKeyMultibase
* value to multibaseValue.
*
* Note: This implementation does not currently support the Multikey
* format.
*/
if (publicKeyFormat === 'X25519KeyAgreementKey2020') {
verificationMethod.publicKeyMultibase = kemMultibaseValue;
}
/**
* 12. If publicKeyFormat is JsonWebKey2020, set the verificationMethod.publicKeyJwk value to
* the result of passing multicodecValue and rawPublicKeyBytes to a JWK encoding algorithm.
*/
if (publicKeyFormat === 'JsonWebKey2020') {
const { crv } = yield DidKeyUtils.multicodecToJwk({ code: multicodecValue });
verificationMethod.publicKeyJwk = yield DidKeyUtils.keyConverter(crv).bytesToPublicKey({ publicKeyBytes });
}
/**
* 13. Return verificationMethod.
*/
return verificationMethod;
});
}
/**
* Decodes a multibase-encoded multicodec value into a verification method
* that is suitable for verifying digital signatures.
* @param options - Signature method creation algorithm inputs.
* @returns - A verification method.
*/
static createSignatureMethod(_a) {
return __awaiter(this, arguments, void 0, function* ({ didUri, multibaseValue, options }) {
const { enableExperimentalPublicKeyTypes, publicKeyFormat } = options;
/**
* 1. Initialize verificationMethod to an empty object.
*/
const verificationMethod = { id: '', type: '', controller: '' };
/**
* 2. Set multicodecValue and publicKeyBytes to the result of passing
* multibaseValue and options to a Decode Public Key algorithm.
*/
const { keyBytes: publicKeyBytes, multicodecCode: multicodecValue, multicodecName } = multibaseIdToKeyBytes({ multibaseKeyId: multibaseValue });
/**
* 3. Ensure the proper key length of publicKeyBytes based on the multicodecValue
* {@link https://w3c-ccg.github.io/did-method-key/#signature-method-creation-algorithm | table provided}.
* If the byte length of rawPublicKeyBytes does not match the expected public key length for the
* associated multicodecValue, an invalidPublicKeyLength error MUST be raised.
*/
const actualLength = publicKeyBytes.byteLength;
const expectedLength = DidKeyUtils.MULTICODEC_PUBLIC_KEY_LENGTH[multicodecValue];
if (actualLength !== expectedLength) {
throw new DidError(DidErrorCode.InvalidPublicKeyLength, `Expected ${actualLength} bytes. Actual: ${expectedLength}`);
}
/**
* 4. Ensure the publicKeyBytes are a proper encoding of the public key type as specified by
* the multicodecValue. If an invalid public key value is detected, an invalidPublicKey error
* MUST be raised.
*/
let isValid = false;
switch (multicodecName) {
case 'secp256k1-pub':
isValid = yield Secp256k1.validatePublicKey({ publicKeyBytes });
break;
case 'ed25519-pub':
isValid = yield Ed25519.validatePublicKey({ publicKeyBytes });
break;
case 'x25519-pub':
// TODO: Validate key once/if X25519.validatePublicKey() is implemented.
// isValid = X25519.validatePublicKey({ key: rawPublicKeyBytes})
isValid = true;
break;
}
if (!isValid) {
throw new DidError(DidErrorCode.InvalidPublicKey, 'Invalid public key detected.');
}
/**
* 5. Set the verificationMethod.id value by concatenating identifier, a hash character (#), and
* the multibaseValue. If verificationMethod.id is not a valid DID URL, an invalidDidUrl error
* MUST be raised.
*/
verificationMethod.id = `${didUri}#${multibaseValue}`;
try {
new URL(verificationMethod.id);
}
catch (error) {
throw new DidError(DidErrorCode.InvalidDidUrl, 'Verification Method ID is not a valid DID URL.');
}
/**
* 6. Set the publicKeyFormat value to the options.publicKeyFormat value.
* 7. If publicKeyFormat is not known to the implementation, an unsupportedPublicKeyType error
* MUST be raised.
*/
if (!(publicKeyFormat in DidKeyVerificationMethodType)) {
throw new DidError(DidErrorCode.UnsupportedPublicKeyType, `Unsupported format: ${publicKeyFormat}`);
}
/**
* 8. If options.enableExperimentalPublicKeyTypes is set to false and publicKeyFormat is not
* Multikey, JsonWebKey2020, or Ed25519VerificationKey2020, an invalidPublicKeyType error MUST
* be raised.
*/
const StandardPublicKeyTypes = ['Multikey', 'JsonWebKey2020', 'Ed25519VerificationKey2020'];
if (enableExperimentalPublicKeyTypes === false
&& !(StandardPublicKeyTypes.includes(publicKeyFormat))) {
throw new DidError(DidErrorCode.InvalidPublicKeyType, `Specified '${publicKeyFormat}' without setting enableExperimentalPublicKeyTypes to true.`);
}
/**
* 9. Set verificationMethod.type to the publicKeyFormat value.
*/
verificationMethod.type = publicKeyFormat;
/**
* 10. Set verificationMethod.controller to the identifier value.
*/
verificationMethod.controller = didUri;
/**
* 11. If publicKeyFormat is Multikey or Ed25519VerificationKey2020,
* set the verificationMethod.publicKeyMultibase value to multibaseValue.
*
* Note: This implementation does not currently support the Multikey
* format.
*/
if (publicKeyFormat === 'Ed25519VerificationKey2020') {
verificationMethod.publicKeyMultibase = multibaseValue;
}
/**
* 12. If publicKeyFormat is JsonWebKey2020, set the verificationMethod.publicKeyJwk value to
* the result of passing multicodecValue and rawPublicKeyBytes to a JWK encoding algorithm.
*/
if (publicKeyFormat === 'JsonWebKey2020') {
const { crv } = yield DidKeyUtils.multicodecToJwk({ code: multicodecValue });
verificationMethod.publicKeyJwk = yield DidKeyUtils.keyConverter(crv).bytesToPublicKey({ publicKeyBytes });
}
/**
* 13. Return verificationMethod.
*/
return verificationMethod;
});
}
/**
* Transform a multibase-encoded multicodec value to public encryption key
* components that are suitable for encrypting messages to a receiver. A
* mathematical proof elaborating on the safety of performing this operation
* is available in:
* {@link https://eprint.iacr.org/2021/509.pdf | On using the same key pair for Ed25519 and an X25519 based KEM}
*/
static deriveEncryptionKey(_a) {
return __awaiter(this, arguments, void 0, function* ({ multibaseValue }) {
/**
* 1. Set publicEncryptionKey to an empty object.
*/
let publicEncryptionKey = {
keyBytes: new Uint8Array(),
multicodecCode: 0
};
/**
* 2. Decode multibaseValue using the base58-btc multibase alphabet and
* set multicodecValue to the multicodec header for the decoded value.
* Implementers are cautioned to ensure that the multicodecValue is set
* to the result after performing varint decoding.
*
* 3. Set the rawPublicKeyBytes to the bytes remaining after the multicodec
* header.
*/
const { keyBytes: publicKeyBytes, multicodecCode: multicodecValue } = multibaseIdToKeyBytes({ multibaseKeyId: multibaseValue });
/**
* 4. If the multicodecValue is 0xed (Ed25519 public key), derive a public X25519 encryption key
* by using the raw publicKeyBytes and the algorithm defined in
* {@link https://datatracker.ietf.org/doc/html/draft-ietf-core-oscore-groupcomm | Group OSCORE - Secure Group Communication for CoAP}
* for Curve25519 in Section 2.4.2: ECDH with Montgomery Coordinates and set
* generatedPublicEncryptionKeyBytes to the result.
*/
if (multicodecValue === 0xed) {
const ed25519PublicKey = yield DidKeyUtils.keyConverter('Ed25519').bytesToPublicKey({
publicKeyBytes
});
const generatedPublicEncryptionKey = yield Ed25519.convertPublicKeyToX25519({
publicKey: ed25519PublicKey
});
const generatedPublicEncryptionKeyBytes = yield DidKeyUtils.keyConverter('Ed25519').publicKeyToBytes({
publicKey: generatedPublicEncryptionKey
});
/**
* 5. Set multicodecValue to 0xec.
* 6. Set raw public keyBytes to generatedPublicEncryptionKeyBytes.
*/
publicEncryptionKey = {
keyBytes: generatedPublicEncryptionKeyBytes,
multicodecCode: 0xec
};
}
/**
* 7. Return publicEncryptionKey.
*/
return publicEncryptionKey;
});
}
/**
* Validates the structure and components of a DID URI against the `did:key` method specification.
*
* @param parsedDid - An object representing the parsed components of a DID URI, including the
* scheme, method, and method-specific identifier.
* @returns `true` if the DID URI meets the `did:key` method's structural requirements, `false` otherwise.
*
*/
static validateIdentifier(parsedDid) {
const { method, id: multibaseValue } = parsedDid;
const [scheme] = parsedDid.uri.split(':', 1);
/**
* Note: The W3C DID specification makes no mention of a version value being part of the DID
* syntax. Additionally, there does not appear to be any real-world usage of the version
* number. Consequently, this implementation will ignore the version related guidance in
* the did:key specification.
*/
const version = '1';
return (scheme === 'did' &&
method === 'key' &&
Number(version) > 0 &&
universalTypeOf(multibaseValue) === 'String' &&
multibaseValue.startsWith('z'));
}
}
/**
* Name of the DID method, as defined in the DID Key specification.
*/
DidKey.methodName = 'key';
/**
* The `DidKeyUtils` class provides utility functions to support operations in the DID Key method.
*/
export class DidKeyUtils {
/**
* Converts a JWK (JSON Web Key) to a Multicodec code and name.
*
* @example
* ```ts
* const jwk: Jwk = { crv: 'Ed25519', kty: 'OKP', x: '...' };
* const { code, name } = await DidKeyUtils.jwkToMulticodec({ jwk });
* ```
*
* @param params - The parameters for the conversion.
* @param params.jwk - The JSON Web Key to be converted.
* @returns A promise that resolves to a Multicodec definition.
*/
static jwkToMulticodec(_a) {
return __awaiter(this, arguments, void 0, function* ({ jwk }) {
const params = [];
if (jwk.crv) {
params.push(jwk.crv);
if (jwk.d) {
params.push('private');
}
else {
params.push('public');
}
}
const lookupKey = params.join(':');
const name = DidKeyUtils.JWK_TO_MULTICODEC[lookupKey];
if (name === undefined) {
throw new Error(`Unsupported JWK to Multicodec conversion: '${lookupKey}'`);
}
const code = Multicodec.getCodeFromName({ name });
return { code, name };
});
}
/**
* Returns the appropriate public key compressor for the specified cryptographic curve.
*
* @param curve - The cryptographic curve to use for the key conversion.
* @returns A public key compressor for the specified curve.
*/
static keyCompressor(curve) {
// ): ({ publicKeyBytes }: { publicKeyBytes: Uint8Array }) => Promise<Uint8Array> {
const compressors = {
'P-256': Secp256r1.compressPublicKey,
'secp256k1': Secp256k1.compressPublicKey
};
const compressor = compressors[curve];
if (!compressor)
throw new DidError(DidErrorCode.InvalidPublicKeyType, `Unsupported curve: ${curve}`);
return compressor;
}
/**
* Returns the appropriate key converter for the specified cryptographic curve.
*
* @param curve - The cryptographic curve to use for the key conversion.
* @returns An `AsymmetricKeyConverter` for the specified curve.
*/
static keyConverter(curve) {
const converters = {
'Ed25519': Ed25519,
'P-256': Secp256r1,
'secp256k1': Secp256k1,
'X25519': X25519
};
const converter = converters[curve];
if (!converter)
throw new DidError(DidErrorCode.InvalidPublicKeyType, `Unsupported curve: ${curve}`);
return converter;
}
/**
* Converts a Multicodec code or name to parial JWK (JSON Web Key).
*
* @example
* ```ts
* const partialJwk = await DidKeyUtils.multicodecToJwk({ name: 'ed25519-pub' });
* ```
*
* @param params - The parameters for the conversion.
* @param params.code - Optional Multicodec code to convert.
* @param params.name - Optional Multicodec name to convert.
* @returns A promise that resolves to a JOSE format key.
*/
static multicodecToJwk(_a) {
return __awaiter(this, arguments, void 0, function* ({ code, name }) {
// Either code or name must be specified, but not both.
if (!(name ? !code : code)) {
throw new Error(`Either 'name' or 'code' must be defined, but not both.`);
}
// If name is undefined, lookup by code.
name = (name === undefined) ? Multicodec.getNameFromCode({ code: code }) : name;
const lookupKey = name;
const jose = DidKeyUtils.MULTICODEC_TO_JWK[lookupKey];
if (jose === undefined) {
throw new Error(`Unsupported Multicodec to JWK conversion`);
}
return Object.assign({}, jose);
});
}
/**
* Converts a public key in JWK (JSON Web Key) format to a multibase identifier.
*
* @remarks
* Note: All secp public keys are converted to compressed point encoding
* before the multibase identifier is computed.
*
* Per {@link https://github.com/multiformats/multicodec/blob/master/table.csv | Multicodec table}:
* Public keys for Elliptic Curve cryptography algorithms (e.g., secp256k1,
* secp256k1r1, secp384r1, etc.) are always represented with compressed point
* encoding (e.g., secp256k1-pub, p256-pub, p384-pub, etc.).
*
* Per {@link https://datatracker.ietf.org/doc/html/rfc8812#name-jose-and-cose-secp256k1-cur | RFC 8812}:
* "As a compressed point encoding representation is not defined for JWK
* elliptic curve points, the uncompressed point encoding defined there
* MUST be used. The x and y values represented MUST both be exactly
* 256 bits, with any leading zeros preserved."
*
* @example
* ```ts
* const publicKey = { crv: 'Ed25519', kty: 'OKP', x: '...' };
* const multibaseId = await DidKeyUtils.publicKeyToMultibaseId({ publicKey });
* ```
*
* @param params - The parameters for the conversion.
* @param params.publicKey - The public key in JWK format.
* @returns A promise that resolves to the multibase identifier.
*/
static publicKeyToMultibaseId(_a) {
return __awaiter(this, arguments, void 0, function* ({ publicKey }) {
var _b;
if (!((publicKey === null || publicKey === void 0 ? void 0 : publicKey.crv) && publicKey.crv in AlgorithmToKeyTypeMap)) {
throw new DidError(DidErrorCode.InvalidPublicKeyType, `Public key contains an unsupported key type: ${(_b = publicKey === null || publicKey === void 0 ? void 0 : publicKey.crv) !== null && _b !== void 0 ? _b : 'undefined'}`);
}
// Convert the public key from JWK format to a byte array.
let publicKeyBytes = yield DidKeyUtils.keyConverter(publicKey.crv).publicKeyToBytes({ publicKey });
// Compress the public key if it is an elliptic curve key.
if (/^(secp256k1|P-256|P-384|P-521)$/.test(publicKey.crv)) {
publicKeyBytes = yield DidKeyUtils.keyCompressor(publicKey.crv)({ publicKeyBytes });
}
// Convert the JSON Web Key (JWK) parameters to a Multicodec name.
const { name: multicodecName } = yield DidKeyUtils.jwkToMulticodec({ jwk: publicKey });
// Compute the multibase identifier based on the provided key.
const multibaseId = keyBytesToMultibaseId({
keyBytes: publicKeyBytes,
multicodecName
});
return multibaseId;
});
}
}
/**
* A mapping from JSON Web Key (JWK) property descriptors to multicodec names.
*
* This mapping is used to convert keys in JWK (JSON Web Key) format to multicodec format.
*
* @remarks
* The keys of this object are strings that describe the JOSE key type and usage,
* such as 'Ed25519:public', 'Ed25519:private', etc. The values are the corresponding multicodec
* names used to represent these key types.
*
* @example
* ```ts
* const multicodecName = JWK_TO_MULTICODEC['Ed25519:public'];
* // Returns 'ed25519-pub', the multicodec name for an Ed25519 public key
* ```
*/
DidKeyUtils.JWK_TO_MULTICODEC = {
'Ed25519:public': 'ed25519-pub',
'Ed25519:private': 'ed25519-priv',
'secp256k1:public': 'secp256k1-pub',
'secp256k1:private': 'secp256k1-priv',
'X25519:public': 'x25519-pub',
'X25519:private': 'x25519-priv',
};
/**
* Defines the expected byte lengths for public keys associated with different cryptographic
* algorithms, indexed by their multicodec code values.
*/
DidKeyUtils.MULTICODEC_PUBLIC_KEY_LENGTH = {
// secp256k1-pub - Secp256k1 public key (compressed) - 33 bytes
0xe7: 33,
// x25519-pub - Curve25519 public key - 32 bytes
0xec: 32,
// ed25519-pub - Ed25519 public key - 32 bytes
0xed: 32
};
/**
* A mapping from multicodec names to their corresponding JOSE (JSON Object Signing and Encryption)
* representations. This mapping facilitates the conversion of multicodec key formats to
* JWK (JSON Web Key) formats.
*
* @remarks
* The keys of this object are multicodec names, such as 'ed25519-pub', 'ed25519-priv', etc.
* The values are objects representing the corresponding JWK properties for that key type.
*
* @example
* ```ts
* const joseKey = MULTICODEC_TO_JWK['ed25519-pub'];
* // Returns a partial JWK for an Ed25519 public key
* ```
*/
DidKeyUtils.MULTICODEC_TO_JWK = {
'ed25519-pub': { crv: 'Ed25519', kty: 'OKP', x: '' },
'ed25519-priv': { crv: 'Ed25519', kty: 'OKP', x: '', d: '' },
'secp256k1-pub': { crv: 'secp256k1', kty: 'EC', x: '', y: '' },
'secp256k1-priv': { crv: 'secp256k1', kty: 'EC', x: '', y: '', d: '' },
'x25519-pub': { crv: 'X25519', kty: 'OKP', x: '' },
'x25519-priv': { crv: 'X25519', kty: 'OKP', x: '', d: '' },
};
//# sourceMappingURL=did-key.js.map
File diff suppressed because one or more lines are too long
+53
View File
@@ -0,0 +1,53 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
/**
* Base abstraction for all Decentralized Identifier (DID) method implementations.
*
* This base class serves as a foundational structure upon which specific DID methods
* can be implemented. Subclasses should furnish particular method and data models adherent
* to various DID methods, taking care to adhere to the
* {@link https://www.w3.org/TR/did-core/ | W3C DID Core specification} and the
* respective DID method specifications.
*/
export class DidMethod {
/**
* MUST be implemented by all DID method implementations that extend {@link DidMethod}.
*
* Given the W3C DID Document of a DID, return the verification method that will be used for
* signing messages and credentials. If given, the `methodId` parameter is used to select the
* verification method. If not given, each DID method implementation will select a default
* verification method from the DID Document.
*
* @param _params - The parameters for the `getSigningMethod` operation.
* @param _params.didDocument - DID Document to get the verification method from.
* @param _params.methodId - ID of the verification method to use for signing.
* @returns Verification method to use for signing.
*/
static getSigningMethod(_params) {
return __awaiter(this, void 0, void 0, function* () {
throw new Error(`Not implemented: Classes extending DidMethod must implement getSigningMethod()`);
});
}
/**
* MUST be implemented by all DID method implementations that extend {@link DidMethod}.
*
* Resolves a DID URI to a DID Document.
*
* @param _didUri - The DID to be resolved.
* @param _options - Optional parameters for resolving the DID.
* @returns A Promise resolving to a {@link DidResolutionResult} object representing the result of the resolution.
*/
static resolve(_didUri, _options) {
return __awaiter(this, void 0, void 0, function* () {
throw new Error(`Not implemented: Classes extending DidMethod must implement resolve()`);
});
}
}
//# sourceMappingURL=did-method.js.map
@@ -0,0 +1 @@
{"version":3,"file":"did-method.js","sourceRoot":"","sources":["../../../src/methods/did-method.ts"],"names":[],"mappings":";;;;;;;;;AAyOA;;;;;;;;GAQG;AACH,MAAM,OAAO,SAAS;IACpB;;;;;;;;;;;;OAYG;IACI,MAAM,CAAO,gBAAgB,CAAC,OAGpC;;YACC,MAAM,IAAI,KAAK,CAAC,gFAAgF,CAAC,CAAC;QACpG,CAAC;KAAA;IAED;;;;;;;;OAQG;IACI,MAAM,CAAO,OAAO,CAAC,OAAe,EAAE,QAA+B;;YAC1E,MAAM,IAAI,KAAK,CAAC,uEAAuE,CAAC,CAAC;QAC3F,CAAC;KAAA;CACF"}
+83
View File
@@ -0,0 +1,83 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Did } from '../did.js';
import { DidMethod } from './did-method.js';
import { EMPTY_DID_RESOLUTION_RESULT } from '../types/did-resolution.js';
/**
* The `DidWeb` class provides an implementation of the `did:web` DID method.
*
* Features:
* - DID Resolution: Resolve a `did:web` to its corresponding DID Document.
*
* @remarks
* The `did:web` method uses a web domain's existing reputation and aims to integrate decentralized
* identities with the existing web infrastructure to drive adoption. It leverages familiar web
* security models and domain ownership to provide accessible, interoperable digital identity
* management.
*
* @see {@link https://w3c-ccg.github.io/did-method-web/ | DID Web Specification}
*
* @example
* ```ts
* // DID Resolution
* const resolutionResult = await DidWeb.resolve({ did: did.uri });
* ```
*/
export class DidWeb extends DidMethod {
/**
* Resolves a `did:web` identifier to a DID Document.
*
* @param didUri - The DID to be resolved.
* @param _options - Optional parameters for resolving the DID. Unused by this DID method.
* @returns A Promise resolving to a {@link DidResolutionResult} object representing the result of the resolution.
*/
static resolve(didUri, _options) {
return __awaiter(this, void 0, void 0, function* () {
// Attempt to parse the DID URI.
const parsedDid = Did.parse(didUri);
// If parsing failed, the DID is invalid.
if (!parsedDid) {
return Object.assign(Object.assign({}, EMPTY_DID_RESOLUTION_RESULT), { didResolutionMetadata: { error: 'invalidDid' } });
}
// If the DID method is not "web", return an error.
if (parsedDid.method !== DidWeb.methodName) {
return Object.assign(Object.assign({}, EMPTY_DID_RESOLUTION_RESULT), { didResolutionMetadata: { error: 'methodNotSupported' } });
}
// Replace ":" with "/" in the identifier and prepend "https://" to obtain the fully qualified
// domain name and optional path.
let baseUrl = `https://${parsedDid.id.replace(/:/g, '/')}`;
// If the domain contains a percent encoded port value, decode the colon.
baseUrl = decodeURIComponent(baseUrl);
// Append the expected location of the DID document depending on whether a path was specified.
const didDocumentUrl = parsedDid.id.includes(':') ?
`${baseUrl}/did.json` :
`${baseUrl}/.well-known/did.json`;
try {
// Perform an HTTP GET request to obtain the DID document.
const response = yield fetch(didDocumentUrl);
// If the response status code is not 200, return an error.
if (!response.ok)
throw new Error('HTTP error status code returned');
// Parse the DID document.
const didDocument = yield response.json();
return Object.assign(Object.assign({}, EMPTY_DID_RESOLUTION_RESULT), { didDocument });
}
catch (error) {
// If the DID document could not be retrieved, return an error.
return Object.assign(Object.assign({}, EMPTY_DID_RESOLUTION_RESULT), { didResolutionMetadata: { error: 'notFound' } });
}
});
}
}
/**
* Name of the DID method, as defined in the DID Web specification.
*/
DidWeb.methodName = 'web';
//# sourceMappingURL=did-web.js.map
@@ -0,0 +1 @@
{"version":3,"file":"did-web.js","sourceRoot":"","sources":["../../../src/methods/did-web.ts"],"names":[],"mappings":";;;;;;;;;AAEA,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AAEzE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,OAAO,MAAO,SAAQ,SAAS;IAOnC;;;;;;OAMG;IACI,MAAM,CAAO,OAAO,CAAC,MAAc,EAAE,QAA+B;;YACzE,gCAAgC;YAChC,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAEpC,yCAAyC;YACzC,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,uCACK,2BAA2B,KAC9B,qBAAqB,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,IAC9C;YACJ,CAAC;YAED,mDAAmD;YACnD,IAAI,SAAS,CAAC,MAAM,KAAK,MAAM,CAAC,UAAU,EAAE,CAAC;gBAC3C,uCACK,2BAA2B,KAC9B,qBAAqB,EAAE,EAAE,KAAK,EAAE,oBAAoB,EAAE,IACtD;YACJ,CAAC;YAED,8FAA8F;YAC9F,iCAAiC;YACjC,IAAI,OAAO,GAAG,WAAW,SAAS,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;YAE3D,yEAAyE;YACzE,OAAO,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;YAEtC,8FAA8F;YAC9F,MAAM,cAAc,GAAG,SAAS,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;gBACjD,GAAG,OAAO,WAAW,CAAC,CAAC;gBACvB,GAAG,OAAO,uBAAuB,CAAC;YAEpC,IAAI,CAAC;gBACH,0DAA0D;gBAC1D,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,cAAc,CAAC,CAAC;gBAE7C,2DAA2D;gBAC3D,IAAI,CAAC,QAAQ,CAAC,EAAE;oBAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;gBAErE,0BAA0B;gBAC1B,MAAM,WAAW,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAiB,CAAC;gBAEzD,uCACK,2BAA2B,KAC9B,WAAW,IACX;YAEJ,CAAC;YAAC,OAAO,KAAU,EAAE,CAAC;gBACpB,+DAA+D;gBAC/D,uCACK,2BAA2B,KAC9B,qBAAqB,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,IAC5C;YACJ,CAAC;QACH,CAAC;KAAA;;AAlED;;GAEG;AACW,iBAAU,GAAG,KAAK,CAAC"}
@@ -0,0 +1,101 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import ms from 'ms';
import { Level } from 'level';
/**
* A Level-based cache implementation for storing and retrieving DID resolution results.
*
* This cache uses LevelDB for storage, allowing data persistence across process restarts or
* browser refreshes. It's suitable for both Node.js and browser environments.
*
* @remarks
* The LevelDB cache keeps data in memory for fast access and also writes to the filesystem in
* Node.js or indexedDB in browsers. Time-to-live (TTL) for cache entries is configurable.
*
* @example
* ```
* const cache = new DidResolverCacheLevel({ ttl: '15m' });
* ```
*/
export class DidResolverCacheLevel {
constructor({ db, location = 'DATA/DID_RESOLVERCACHE', ttl = '15m' } = {}) {
this.cache = db !== null && db !== void 0 ? db : new Level(location);
this.ttl = ms(ttl);
}
/**
* Retrieves a DID resolution result from the cache.
*
* If the cached item has exceeded its TTL, it's scheduled for deletion and undefined is returned.
*
* @param did - The DID string used as the key for retrieving the cached result.
* @returns The cached DID resolution result or undefined if not found or expired.
*/
get(did) {
return __awaiter(this, void 0, void 0, function* () {
try {
const str = yield this.cache.get(did);
const cachedDidResolutionResult = JSON.parse(str);
if (Date.now() >= cachedDidResolutionResult.ttlMillis) {
// defer deletion to be called in the next tick of the js event loop
this.cache.nextTick(() => this.cache.del(did));
return;
}
else {
return cachedDidResolutionResult.value;
}
}
catch (error) {
// Don't throw when a key wasn't found.
if (error.notFound) {
return;
}
throw error;
}
});
}
/**
* Stores a DID resolution result in the cache with a TTL.
*
* @param did - The DID string used as the key for storing the result.
* @param value - The DID resolution result to be cached.
* @returns A promise that resolves when the operation is complete.
*/
set(did, value) {
const cachedDidResolutionResult = { ttlMillis: Date.now() + this.ttl, value };
const str = JSON.stringify(cachedDidResolutionResult);
return this.cache.put(did, str);
}
/**
* Deletes a DID resolution result from the cache.
*
* @param did - The DID string used as the key for deletion.
* @returns A promise that resolves when the operation is complete.
*/
delete(did) {
return this.cache.del(did);
}
/**
* Clears all entries from the cache.
*
* @returns A promise that resolves when the operation is complete.
*/
clear() {
return this.cache.clear();
}
/**
* Closes the underlying LevelDB store.
*
* @returns A promise that resolves when the store is closed.
*/
close() {
return this.cache.close();
}
}
//# sourceMappingURL=resolver-cache-level.js.map
@@ -0,0 +1 @@
{"version":3,"file":"resolver-cache-level.js","sourceRoot":"","sources":["../../../src/resolver/resolver-cache-level.ts"],"names":[],"mappings":";;;;;;;;;AAEA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAuD9B;;;;;;;;;;;;;;GAcG;AACH,MAAM,OAAO,qBAAqB;IAOhC,YAAY,EACV,EAAE,EACF,QAAQ,GAAG,wBAAwB,EACnC,GAAG,GAAG,KAAK,KACoB,EAAE;QACjC,IAAI,CAAC,KAAK,GAAG,EAAE,aAAF,EAAE,cAAF,EAAE,GAAI,IAAI,KAAK,CAAiB,QAAQ,CAAC,CAAC;QACvD,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;IACrB,CAAC;IAED;;;;;;;OAOG;IACG,GAAG,CAAC,GAAW;;YACnB,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBACtC,MAAM,yBAAyB,GAA8B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAE7E,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,yBAAyB,CAAC,SAAS,EAAE,CAAC;oBACtD,oEAAoE;oBACpE,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;oBAE/C,OAAO;gBACT,CAAC;qBAAM,CAAC;oBACN,OAAO,yBAAyB,CAAC,KAAK,CAAC;gBACzC,CAAC;YAEH,CAAC;YAAC,OAAM,KAAU,EAAE,CAAC;gBACnB,uCAAuC;gBACvC,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;oBACnB,OAAO;gBACT,CAAC;gBAED,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;KAAA;IAED;;;;;;OAMG;IACH,GAAG,CAAC,GAAW,EAAE,KAA0B;QACzC,MAAM,yBAAyB,GAA8B,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC;QACzG,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,yBAAyB,CAAC,CAAC;QAEtD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAClC,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,GAAW;QAChB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED;;;;OAIG;IACH,KAAK;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IAC5B,CAAC;IAED;;;;OAIG;IACH,KAAK;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IAC5B,CAAC;CACF"}
@@ -0,0 +1,24 @@
/**
* No-op cache that is used as the default cache for did-resolver.
*
* The motivation behind using a no-op cache as the default stems from the desire to maximize the
* potential for this library to be used in as many JS runtimes as possible.
*/
export const DidResolverCacheNoop = {
get: function (_key) {
return null;
},
set: function (_key, _value) {
return null;
},
delete: function (_key) {
return null;
},
clear: function () {
return null;
},
close: function () {
return null;
}
};
//# sourceMappingURL=resolver-cache-noop.js.map
@@ -0,0 +1 @@
{"version":3,"file":"resolver-cache-noop.js","sourceRoot":"","sources":["../../../src/resolver/resolver-cache-noop.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAqB;IACpD,GAAG,EAAE,UAAU,IAAY;QACzB,OAAO,IAAW,CAAC;IACrB,CAAC;IACD,GAAG,EAAE,UAAU,IAAY,EAAE,MAA2B;QACtD,OAAO,IAAW,CAAC;IACrB,CAAC;IACD,MAAM,EAAE,UAAU,IAAY;QAC5B,OAAO,IAAW,CAAC;IACrB,CAAC;IACD,KAAK,EAAE;QACL,OAAO,IAAW,CAAC;IACrB,CAAC;IACD,KAAK,EAAE;QACL,OAAO,IAAW,CAAC;IACrB,CAAC;CACF,CAAC"}
@@ -0,0 +1,187 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Did } from '../did.js';
import { DidErrorCode } from '../did-error.js';
import { DidResolverCacheNoop } from './resolver-cache-noop.js';
import { EMPTY_DID_RESOLUTION_RESULT } from '../types/did-resolution.js';
/**
* The `DidResolver` class provides mechanisms for resolving Decentralized Identifiers (DIDs) to
* their corresponding DID documents.
*
* The class is designed to handle various DID methods by utilizing an array of `DidMethodResolver`
* instances, each responsible for a specific DID method.
*
* Providing a cache implementation can significantly enhance resolution performance by avoiding
* redundant resolutions for previously resolved DIDs. If omitted, a no-operation cache is used,
* which effectively disables caching.
*
* Usage:
* - Construct the `DidResolver` with an array of `DidMethodResolver` instances and an optional cache.
* - Use `resolve` to resolve a DID to its DID Resolution Result.
* - Use `dereference` to extract specific resources from a DID URL, like service endpoints or verification methods.
*
* @example
* ```ts
* const resolver = new DidResolver({
* didResolvers: [<array of DidMethodResolver instances>],
* cache: new DidResolverCacheNoop()
* });
*
* const resolutionResult = await resolver.resolve('did:example:123456');
* const dereferenceResult = await resolver.dereference({ didUri: 'did:example:123456#key-1' });
* ```
*/
export class UniversalResolver {
/**
* Constructs a new `DidResolver`.
*
* @param params - The parameters for constructing the `DidResolver`.
*/
constructor({ cache, didResolvers }) {
/**
* A map to store method resolvers against method names.
*/
this.didResolvers = new Map();
this.cache = cache || DidResolverCacheNoop;
for (const resolver of didResolvers) {
this.didResolvers.set(resolver.methodName, resolver);
}
}
/**
* Resolves a DID to a DID Resolution Result.
*
* If the DID Resolution Result is present in the cache, it returns the cached result. Otherwise,
* it uses the appropriate method resolver to resolve the DID, stores the resolution result in the
* cache, and returns the resolultion result.
*
* @param didUri - The DID or DID URL to resolve.
* @returns A promise that resolves to the DID Resolution Result.
*/
resolve(didUri, options) {
return __awaiter(this, void 0, void 0, function* () {
const parsedDid = Did.parse(didUri);
if (!parsedDid) {
return Object.assign(Object.assign({}, EMPTY_DID_RESOLUTION_RESULT), { didResolutionMetadata: {
error: DidErrorCode.InvalidDid,
errorMessage: `Invalid DID URI: ${didUri}`
} });
}
const resolver = this.didResolvers.get(parsedDid.method);
if (!resolver) {
return Object.assign(Object.assign({}, EMPTY_DID_RESOLUTION_RESULT), { didResolutionMetadata: {
error: DidErrorCode.MethodNotSupported,
errorMessage: `Method not supported: ${parsedDid.method}`
} });
}
const cachedResolutionResult = yield this.cache.get(parsedDid.uri);
if (cachedResolutionResult) {
return cachedResolutionResult;
}
else {
const resolutionResult = yield resolver.resolve(parsedDid.uri, options);
if (!resolutionResult.didResolutionMetadata.error) {
// Cache the resolution result if it was successful.
yield this.cache.set(parsedDid.uri, resolutionResult);
}
return resolutionResult;
}
});
}
/**
* Dereferences a DID (Decentralized Identifier) URL to a corresponding DID resource.
*
* This method interprets the DID URL's components, which include the DID method, method-specific
* identifier, path, query, and fragment, and retrieves the related resource as per the DID Core
* specifications.
*
* The dereferencing process involves resolving the DID contained in the DID URL to a DID document,
* and then extracting the specific part of the document identified by the fragment in the DID URL.
* If no fragment is specified, the entire DID document is returned.
*
* This method supports resolution of different components within a DID document such as service
* endpoints and verification methods, based on their IDs. It accommodates both full and
* DID URLs as specified in the DID Core specification.
*
* More information on DID URL dereferencing can be found in the
* {@link https://www.w3.org/TR/did-core/#did-url-dereferencing | DID Core specification}.
*
* TODO: This is a partial implementation and does not fully implement DID URL dereferencing. (https://github.com/TBD54566975/web5-js/issues/387)
*
* @param didUrl - The DID URL string to dereference.
* @param [_options] - Input options to the dereference function. Optional.
* @returns a {@link DidDereferencingResult}
*/
dereference(didUrl, _options) {
return __awaiter(this, void 0, void 0, function* () {
// Validate the given `didUrl` confirms to the DID URL syntax.
const parsedDidUrl = Did.parse(didUrl);
if (!parsedDidUrl) {
return {
dereferencingMetadata: { error: DidErrorCode.InvalidDidUrl },
contentStream: null,
contentMetadata: {}
};
}
// Obtain the DID document for the input DID by executing DID resolution.
const { didDocument, didResolutionMetadata, didDocumentMetadata } = yield this.resolve(parsedDidUrl.uri);
if (!didDocument) {
return {
dereferencingMetadata: { error: didResolutionMetadata.error },
contentStream: null,
contentMetadata: {}
};
}
// Return the entire DID Document if no query or fragment is present on the DID URL.
if (!parsedDidUrl.fragment || parsedDidUrl.query) {
return {
dereferencingMetadata: { contentType: 'application/did+json' },
contentStream: didDocument,
contentMetadata: didDocumentMetadata
};
}
const { service = [], verificationMethod = [] } = didDocument;
// Create a set of possible id matches. The DID spec allows for an id to be the entire
// did#fragment or just #fragment.
// @see {@link }https://www.w3.org/TR/did-core/#relative-did-urls | Section 3.2.2, Relative DID URLs}.
// Using a Set for fast string comparison since some DID methods have long identifiers.
const idSet = new Set([didUrl, parsedDidUrl.fragment, `#${parsedDidUrl.fragment}`]);
let didResource;
// Find the first matching verification method in the DID document.
for (let vm of verificationMethod) {
if (idSet.has(vm.id)) {
didResource = vm;
break;
}
}
// Find the first matching service in the DID document.
for (let svc of service) {
if (idSet.has(svc.id)) {
didResource = svc;
break;
}
}
if (didResource) {
return {
dereferencingMetadata: { contentType: 'application/did+json' },
contentStream: didResource,
contentMetadata: didResolutionMetadata
};
}
else {
return {
dereferencingMetadata: { error: DidErrorCode.NotFound },
contentStream: null,
contentMetadata: {},
};
}
});
}
}
//# sourceMappingURL=universal-resolver.js.map
@@ -0,0 +1 @@
{"version":3,"file":"universal-resolver.js","sourceRoot":"","sources":["../../../src/resolver/universal-resolver.ts"],"names":[],"mappings":"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"}
+51
View File
@@ -0,0 +1,51 @@
/**
* Represents the various verification relationships defined in a DID document.
*
* These verification relationships indicate the intended usage of verification methods within a DID
* document. Each relationship signifies a different purpose or context in which a verification
* method can be used, such as authentication, assertionMethod, keyAgreement, capabilityDelegation,
* and capabilityInvocation. The array provides a standardized set of relationship names for
* consistent referencing and implementation across different DID methods.
*
* @see {@link https://www.w3.org/TR/did-core/#verification-relationships | DID Core Specification, § Verification Relationships}
*/
export var DidVerificationRelationship;
(function (DidVerificationRelationship) {
/**
* Specifies how the DID subject is expected to be authenticated. This is commonly used for
* purposes like logging into a website or participating in challenge-response protocols.
*
* @see {@link https://www.w3.org/TR/did-core/#authentication | DID Core Specification, § Authentication}
*/
DidVerificationRelationship["authentication"] = "authentication";
/**
* Specifies how the DID subject is expected to express claims, such as for issuing Verifiable
* Credentials. This relationship is typically used when the DID subject is the issuer of a
* credential.
*
* @see {@link https://www.w3.org/TR/did-core/#assertion | DID Core Specification, § Assertion}
*/
DidVerificationRelationship["assertionMethod"] = "assertionMethod";
/**
* Specifies how an entity can generate encryption material to communicate confidentially with the
* DID subject. Often used in scenarios requiring secure communication channels.
*
* @see {@link https://www.w3.org/TR/did-core/#key-agreement | DID Core Specification, § Key Agreement}
*/
DidVerificationRelationship["keyAgreement"] = "keyAgreement";
/**
* Specifies a verification method used by the DID subject to invoke a cryptographic capability.
* This is frequently associated with authorization actions, like updating the DID Document.
*
* @see {@link https://www.w3.org/TR/did-core/#capability-invocation | DID Core Specification, § Capability Invocation}
*/
DidVerificationRelationship["capabilityInvocation"] = "capabilityInvocation";
/**
* Specifies a mechanism used by the DID subject to delegate a cryptographic capability to another
* party. This can include delegating access to a specific resource or API.
*
* @see {@link https://www.w3.org/TR/did-core/#capability-delegation | DID Core Specification, § Capability Delegation}
*/
DidVerificationRelationship["capabilityDelegation"] = "capabilityDelegation";
})(DidVerificationRelationship || (DidVerificationRelationship = {}));
//# sourceMappingURL=did-core.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"did-core.js","sourceRoot":"","sources":["../../../src/types/did-core.ts"],"names":[],"mappings":"AA+gBA;;;;;;;;;;GAUG;AACH,MAAM,CAAN,IAAY,2BAyCX;AAzCD,WAAY,2BAA2B;IACrC;;;;;OAKG;IACH,gEAAiC,CAAA;IAEjC;;;;;;OAMG;IACH,kEAAmC,CAAA;IAEnC;;;;;OAKG;IACH,4DAA6B,CAAA;IAE7B;;;;;OAKG;IACH,4EAA6C,CAAA;IAE7C;;;;;OAKG;IACH,4EAA6C,CAAA;AAC/C,CAAC,EAzCW,2BAA2B,KAA3B,2BAA2B,QAyCtC"}
+12
View File
@@ -0,0 +1,12 @@
/**
* A constant representing an empty DID Resolution Result. This object is used as the basis for a
* result of DID resolution and is typically augmented with additional properties by the
* DID method resolver.
*/
export const EMPTY_DID_RESOLUTION_RESULT = {
'@context': 'https://w3id.org/did-resolution/v1',
didResolutionMetadata: {},
didDocument: null,
didDocumentMetadata: {},
};
//# sourceMappingURL=did-resolution.js.map
@@ -0,0 +1 @@
{"version":3,"file":"did-resolution.js","sourceRoot":"","sources":["../../../src/types/did-resolution.ts"],"names":[],"mappings":"AAkFA;;;;GAIG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAwB;IAC9D,UAAU,EAAc,oCAAoC;IAC5D,qBAAqB,EAAG,EAAE;IAC1B,WAAW,EAAa,IAAI;IAC5B,mBAAmB,EAAK,EAAE;CAC3B,CAAC"}
+2
View File
@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=multibase.js.map
@@ -0,0 +1 @@
{"version":3,"file":"multibase.js","sourceRoot":"","sources":["../../../src/types/multibase.ts"],"names":[],"mappings":""}
+2
View File
@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=portable-did.js.map
@@ -0,0 +1 @@
{"version":3,"file":"portable-did.js","sourceRoot":"","sources":["../../../src/types/portable-did.ts"],"names":[],"mappings":""}
+458
View File
@@ -0,0 +1,458 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Convert, Multicodec } from '@web5/common';
import { computeJwkThumbprint } from '@web5/crypto';
import { DidError, DidErrorCode } from './did-error.js';
import { DidVerificationRelationship, } from './types/did-core.js';
/**
* Extracts the fragment part of a Decentralized Identifier (DID) verification method identifier.
*
* This function takes any input and aims to return only the fragment of a DID identifier,
* which comes after the '#' symbol in a DID string. It's designed specifically for handling
* DID verification method identifiers. The function returns undefined for non-string inputs, inputs
* that do not contain a '#', or complex data structures like objects or arrays, ensuring that only
* the fragment part of a DID string is extracted when present.
*
* @example
* ```ts
* console.log(extractDidFragment("did:example:123#key-1")); // Output: "key-1"
* console.log(extractDidFragment("did:example:123")); // Output: undefined
* console.log(extractDidFragment({ id: "did:example:123#0", type: "JsonWebKey" })); // Output: undefined
* console.log(extractDidFragment(undefined)); // Output: undefined
* ```
*
* @param input - The input to be processed. Can be of any type, but the function is designed
* to work with strings that represent DID verification method identifiers.
* @returns The fragment part of the DID identifier if the input is a string containing a '#'.
* Returns an empty string for all other inputs, including non-string types, strings
* without a '#', and complex data structures.
*/
export function extractDidFragment(input) {
if (typeof input !== 'string')
return undefined;
if (input.length === 0)
return undefined;
return input.split('#').pop();
}
/**
* Retrieves services from a given DID document, optionally filtered by `id` or `type`.
*
* If no `id` or `type` filters are provided, all defined services are returned.
*
* The given DID Document must adhere to the
* {@link https://www.w3.org/TR/did-core/ | W3C DID Core Specification}.
*
* @example
* ```ts
* const didDocument = { ... }; // W3C DID document
* const services = getServices({ didDocument, type: 'DecentralizedWebNode' });
* ```
*
* @param params - An object containing input parameters for retrieving services.
* @param params.didDocument - The DID document from which services are retrieved.
* @param params.id - Optional. A string representing the specific service ID to match. If provided, only the service with this ID will be returned.
* @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.
* @returns An array of services. If no matching service is found, an empty array is returned.
*/
export function getServices({ didDocument, id, type }) {
var _a, _b;
return (_b = (_a = didDocument === null || didDocument === void 0 ? void 0 : didDocument.service) === null || _a === void 0 ? void 0 : _a.filter(service => {
if (id && service.id !== id)
return false;
if (type && service.type !== type)
return false;
return true;
})) !== null && _b !== void 0 ? _b : [];
}
/**
* Retrieves a verification method object from a DID document if there is a match for the given
* public key.
*
* This function searches the verification methods in a given DID document for a match with the
* provided public key (either in JWK or multibase format). If a matching verification method is
* found it is returned. If no match is found `null` is returned.
*
*
* @example
* ```ts
* const didDocument = {
* // ... contents of a DID document ...
* };
* const publicKeyJwk = { kty: 'OKP', crv: 'Ed25519', x: '...' };
*
* const verificationMethod = await getVerificationMethodByKey({
* didDocument,
* publicKeyJwk
* });
* ```
*
* @param params - An object containing input parameters for retrieving the verification method ID.
* @param params.didDocument - The DID document to search for the verification method.
* @param params.publicKeyJwk - The public key in JSON Web Key (JWK) format to match against the verification methods in the DID document.
* @param params.publicKeyMultibase - The public key as a multibase encoded string to match against the verification methods in the DID document.
* @returns A promise that resolves with the matching verification method, or `null` if no match is found.
* @throws Throws an `Error` if the `didDocument` parameter is missing or if the `didDocument` does not contain any verification methods.
*/
export function getVerificationMethodByKey(_a) {
return __awaiter(this, arguments, void 0, function* ({ didDocument, publicKeyJwk, publicKeyMultibase }) {
// Collect all verification methods from the DID document.
const verificationMethods = getVerificationMethods({ didDocument });
for (let method of verificationMethods) {
if (publicKeyJwk && method.publicKeyJwk) {
const publicKeyThumbprint = yield computeJwkThumbprint({ jwk: publicKeyJwk });
if (publicKeyThumbprint === (yield computeJwkThumbprint({ jwk: method.publicKeyJwk }))) {
return method;
}
}
else if (publicKeyMultibase && method.publicKeyMultibase) {
if (publicKeyMultibase === method.publicKeyMultibase) {
return method;
}
}
}
return null;
});
}
/**
* Retrieves all verification methods from a given DID document, including embedded methods.
*
* This function consolidates all verification methods into a single array for easy access and
* processing. It checks both the primary `verificationMethod` array and the individual verification
* relationship properties `authentication`, `assertionMethod`, `keyAgreement`,
* `capabilityInvocation`, and `capabilityDelegation` for embedded methods.
*
* The given DID Document must adhere to the
* {@link https://www.w3.org/TR/did-core/ | W3C DID Core Specification}.
*
* @example
* ```ts
* const didDocument = { ... }; // W3C DID document
* const verificationMethods = getVerificationMethods({ didDocument });
* ```
*
* @param params - An object containing input parameters for retrieving verification methods.
* @param params.didDocument - The DID document from which verification methods are retrieved.
* @returns An array of `DidVerificationMethod`. If no verification methods are found, an empty array is returned.
* @throws Throws an `TypeError` if the `didDocument` parameter is missing.
*/
export function getVerificationMethods({ didDocument }) {
var _a, _b;
if (!didDocument)
throw new TypeError(`Required parameter missing: 'didDocument'`);
const verificationMethods = [];
// Check the 'verificationMethod' array.
verificationMethods.push(...(_b = (_a = didDocument.verificationMethod) === null || _a === void 0 ? void 0 : _a.filter(isDidVerificationMethod)) !== null && _b !== void 0 ? _b : []);
// Check verification relationship properties for embedded verification methods.
Object.keys(DidVerificationRelationship).forEach((relationship) => {
var _a, _b;
verificationMethods.push(...(_b = (_a = didDocument[relationship]) === null || _a === void 0 ? void 0 : _a.filter(isDidVerificationMethod)) !== null && _b !== void 0 ? _b : []);
});
return verificationMethods;
}
/**
* Retrieves all DID verification method types from a given DID document.
*
* The given DID Document must adhere to the
* {@link https://www.w3.org/TR/did-core/ | W3C DID Core Specification}.
*
* @example
* ```ts
* const didDocument = {
* verificationMethod: [
* {
* 'id' : 'did:example:123#key-0',
* 'type' : 'Ed25519VerificationKey2018',
* 'controller' : 'did:example:123',
* 'publicKeyBase58' : '3M5RCDjPTWPkKSN3sxUmmMqHbmRPegYP1tjcKyrDbt9J'
* },
* {
* 'id' : 'did:example:123#key-1',
* 'type' : 'X25519KeyAgreementKey2019',
* 'controller' : 'did:example:123',
* 'publicKeyBase58' : 'FbQWLPRhTH95MCkQUeFYdiSoQt8zMwetqfWoxqPgaq7x'
* },
* {
* 'id' : 'did:example:123#key-3',
* 'type' : 'JsonWebKey2020',
* 'controller' : 'did:example:123',
* 'publicKeyJwk' : {
* 'kty' : 'EC',
* 'crv' : 'P-256',
* 'x' : 'Er6KSSnAjI70ObRWhlaMgqyIOQYrDJTE94ej5hybQ2M',
* 'y' : 'pPVzCOTJwgikPjuUE6UebfZySqEJ0ZtsWFpj7YSPGEk'
* }
* }
* ]
* },
* const vmTypes = getVerificationMethodTypes({ didDocument });
* console.log(vmTypes);
* // Output: ['Ed25519VerificationKey2018', 'X25519KeyAgreementKey2019', 'JsonWebKey2020']
* ```
*
* @param params - An object containing input parameters for retrieving types.
* @param params.didDocument - The DID document from which types are retrieved.
* @returns An array of types. If no types were found, an empty array is returned.
*/
export function getVerificationMethodTypes({ didDocument }) {
// Collect all verification methods from the DID document.
const verificationMethods = getVerificationMethods({ didDocument });
// Map to extract 'type' from each verification method.
const types = verificationMethods.map(method => method.type);
return [...new Set(types)]; // Return only unique types.
}
/**
* Retrieves a list of DID verification relationships by a specific method ID from a DID document.
*
* This function examines the specified DID document to identify any verification relationships
* (e.g., `authentication`, `assertionMethod`) that reference a verification method by its method ID
* or contain an embedded verification method matching the method ID. The method ID is typically a
* fragment of a DID (e.g., `did:example:123#key-1`) that uniquely identifies a verification method
* within the DID document.
*
* The search considers both direct references to verification methods by their IDs and verification
* methods embedded within the verification relationship arrays. It returns an array of
* `DidVerificationRelationship` enums corresponding to the verification relationships that contain
* the specified method ID.
*
* @param params - An object containing input parameters for retrieving verification relationships.
* @param params.didDocument - The DID document to search for verification relationships.
* @param params.methodId - The method ID to search for within the verification relationships.
* @returns An array of `DidVerificationRelationship` enums representing the types of verification
* relationships that reference the specified method ID.
*
* @example
* ```ts
* const didDocument: DidDocument = {
* // ...contents of a DID document...
* };
*
* const relationships = getVerificationRelationshipsById({
* didDocument,
* methodId: 'key-1'
* });
* console.log(relationships);
* // Output might include ['authentication', 'assertionMethod'] if those relationships
* // reference or contain the specified method ID.
* ```
*/
export function getVerificationRelationshipsById({ didDocument, methodId }) {
const relationships = [];
Object.keys(DidVerificationRelationship).forEach((relationship) => {
if (Array.isArray(didDocument[relationship])) {
const relationshipMethods = didDocument[relationship];
const methodIdFragment = extractDidFragment(methodId);
// Check if the verification relationship property contains a matching method ID either
// directly referenced or as an embedded verification method.
const containsMethodId = relationshipMethods.some(method => {
const isByReferenceMatch = extractDidFragment(method) === methodIdFragment;
const isEmbeddedMethodMatch = isDidVerificationMethod(method) && extractDidFragment(method.id) === methodIdFragment;
return isByReferenceMatch || isEmbeddedMethodMatch;
});
if (containsMethodId) {
relationships.push(relationship);
}
}
});
return relationships;
}
/**
* Checks if a given object is a {@link DidService}.
*
* A {@link DidService} in the context of DID resources must include the properties `id`, `type`,
* and `serviceEndpoint`. The `serviceEndpoint` can be a `DidServiceEndpoint` or an array of
* `DidServiceEndpoint` objects.
*
* @example
* ```ts
* const service = {
* id: "did:example:123#service-1",
* type: "OidcService",
* serviceEndpoint: "https://example.com/oidc"
* };
*
* if (isDidService(service)) {
* console.log('The object is a DidService');
* } else {
* console.log('The object is not a DidService');
* }
* ```
*
* @param obj - The object to be checked.
* @returns `true` if `obj` is a `DidService`; otherwise, `false`.
*/
export function isDidService(obj) {
// Validate that the given value is an object.
if (!obj || typeof obj !== 'object' || obj === null)
return false;
// Validate that the object has the necessary properties of DidService.
return 'id' in obj && 'type' in obj && 'serviceEndpoint' in obj;
}
/**
* Checks if a given object is a {@link DwnDidService}.
*
* A {@link DwnDidService} is defined as {@link DidService} object with a `type` of
* "DecentralizedWebNode" and `enc` and `sig` properties, where both properties are either strings
* or arrays of strings.
*
* @example
* ```ts
* const didDocument: DidDocument = {
* id: 'did:example:123',
* verificationMethod: [
* {
* id: 'did:example:123#key-1',
* type: 'JsonWebKey2020',
* controller: 'did:example:123',
* publicKeyJwk: { ... }
* },
* {
* id: 'did:example:123#key-2',
* type: 'JsonWebKey2020',
* controller: 'did:example:123',
* publicKeyJwk: { ... }
* }
* ],
* service: [
* {
* id: 'did:example:123#dwn',
* type: 'DecentralizedWebNode',
* serviceEndpoint: 'https://dwn.tbddev.org/dwn0',
* enc: 'did:example:123#key-1',
* sig: 'did:example:123#key-2'
* }
* ]
* };
*
* if (isDwnService(didDocument.service[0])) {
* console.log('The object is a DwnDidService');
* } else {
* console.log('The object is not a DwnDidService');
* }
* ```
*
* @see {@link https://identity.foundation/decentralized-web-node/spec/ | Decentralized Web Node (DWN) Specification}
*
* @param obj - The object to be checked.
* @returns `true` if `obj` is a DwnDidService; otherwise, `false`.
*/
export function isDwnDidService(obj) {
// Validate that the given value is a {@link DidService}.
if (!isDidService(obj))
return false;
// Validate that the `type` property is `DecentralizedWebNode`.
if (obj.type !== 'DecentralizedWebNode')
return false;
// Validate that the given object has the `enc` and `sig` properties.
if (!('enc' in obj && 'sig' in obj))
return false;
// Validate that the `enc` and `sig` properties are either strings or arrays of strings.
const isStringOrStringArray = (prop) => typeof prop === 'string' || Array.isArray(prop) && prop.every(item => typeof item === 'string');
return (isStringOrStringArray(obj.enc)) && (isStringOrStringArray(obj.sig));
}
/**
* Checks if a given object is a DID Verification Method.
*
* A {@link DidVerificationMethod} in the context of DID resources must include the properties `id`,
* `type`, and `controller`.
*
* @example
* ```ts
* const resource = {
* id : "did:example:123#0",
* type : "JsonWebKey2020",
* controller : "did:example:123",
* publicKeyJwk : { ... }
* };
*
* if (isDidVerificationMethod(resource)) {
* console.log('The resource is a DidVerificationMethod');
* } else {
* console.log('The resource is not a DidVerificationMethod');
* }
* ```
*
* @param obj - The object to be checked.
* @returns `true` if `obj` is a `DidVerificationMethod`; otherwise, `false`.
*/
export function isDidVerificationMethod(obj) {
// Validate that the given value is an object.
if (!obj || typeof obj !== 'object' || obj === null)
return false;
// Validate that the object has the necessary properties of a DidVerificationMethod.
if (!('id' in obj && 'type' in obj && 'controller' in obj))
return false;
if (typeof obj.id !== 'string')
return false;
if (typeof obj.type !== 'string')
return false;
if (typeof obj.controller !== 'string')
return false;
return true;
}
/**
* Converts a cryptographic key to a multibase identifier.
*
* @remarks
* This method provides a way to represent a cryptographic key as a multibase identifier.
* It takes a `Uint8Array` representing the key, and either the multicodec code or multicodec name
* as input. The method first adds the multicodec prefix to the key, then encodes it into Base58
* format. Finally, it converts the Base58 encoded key into a multibase identifier.
*
* @example
* ```ts
* const key = new Uint8Array([...]); // Cryptographic key as Uint8Array
* const multibaseId = keyBytesToMultibaseId({ key, multicodecName: 'ed25519-pub' });
* ```
*
* @param params - The parameters for the conversion.
* @returns The multibase identifier as a string.
*/
export function keyBytesToMultibaseId({ keyBytes, multicodecCode, multicodecName }) {
const prefixedKey = Multicodec.addPrefix({
code: multicodecCode,
data: keyBytes,
name: multicodecName
});
const prefixedKeyB58 = Convert.uint8Array(prefixedKey).toBase58Btc();
const multibaseKeyId = Convert.base58Btc(prefixedKeyB58).toMultibase();
return multibaseKeyId;
}
/**
* Converts a multibase identifier to a cryptographic key.
*
* @remarks
* This function decodes a multibase identifier back into a cryptographic key. It first decodes the
* identifier from multibase format into Base58 format, and then converts it into a `Uint8Array`.
* Afterward, it removes the multicodec prefix, extracting the raw key data along with the
* multicodec code and name.
*
* @example
* ```ts
* const multibaseKeyId = '...'; // Multibase identifier of the key
* const { key, multicodecCode, multicodecName } = multibaseIdToKey({ multibaseKeyId });
* ```
*
* @param params - The parameters for the conversion.
* @param params.multibaseKeyId - The multibase identifier string of the key.
* @returns An object containing the key as a `Uint8Array` and its multicodec code and name.
* @throws `DidError` if the multibase identifier is invalid.
*/
export function multibaseIdToKeyBytes({ multibaseKeyId }) {
try {
const prefixedKeyB58 = Convert.multibase(multibaseKeyId).toBase58Btc();
const prefixedKey = Convert.base58Btc(prefixedKeyB58).toUint8Array();
const { code, data, name } = Multicodec.removePrefix({ prefixedData: prefixedKey });
return { keyBytes: data, multicodecCode: code, multicodecName: name };
}
catch (error) {
throw new DidError(DidErrorCode.InvalidDid, `Invalid multibase identifier: ${multibaseKeyId}`);
}
}
//# sourceMappingURL=utils.js.map
File diff suppressed because one or more lines are too long
+143
View File
@@ -0,0 +1,143 @@
import type { Signer, CryptoApi, KeyIdentifier, KmsExportKeyParams, KmsImportKeyParams, KeyImporterExporter } from '@web5/crypto';
import type { DidDocument } from './types/did-core.js';
import type { DidMetadata, PortableDid } from './types/portable-did.js';
/**
* A `BearerDidSigner` extends the {@link Signer} interface to include specific properties for
* signing with a Decentralized Identifier (DID). It encapsulates the algorithm and key identifier,
* which are often needed when signing JWTs, JWSs, JWEs, and other data structures.
*
* Typically, the algorithm and key identifier are used to populate the `alg` and `kid` fields of a
* JWT or JWS header.
*/
export interface BearerDidSigner extends Signer {
/**
* The cryptographic algorithm identifier used for signing operations.
*
* Typically, this value is used to populate the `alg` field of a JWT or JWS header. The
* registered algorithm names are defined in the
* {@link https://www.iana.org/assignments/jose/jose.xhtml#web-signature-encryption-algorithms | IANA JSON Web Signature and Encryption Algorithms registry}.
*
* @example
* "ES256" // ECDSA using P-256 and SHA-256
*/
algorithm: string;
/**
* The unique identifier of the key within the DID document that is used for signing and
* verification operations.
*
* This identifier must be a DID URI with a fragment (e.g., did:method:123#key-0) that references
* a specific verification method in the DID document. It allows users of a `BearerDidSigner` to
* determine the DID and key that will be used for signing and verification operations.
*
* @example
* "did:dht:123#key-1" // A fragment identifier referring to a key in the DID document
*/
keyId: string;
}
/**
* Represents a Decentralized Identifier (DID) along with its DID document, key manager, metadata,
* and convenience functions.
*/
export declare class BearerDid {
/** {@inheritDoc Did#uri} */
uri: string;
/**
* The DID document associated with this DID.
*
* @see {@link https://www.w3.org/TR/did-core/#dfn-diddocument | DID Core Specification, § DID Document}
*/
document: DidDocument;
/** {@inheritDoc DidMetadata} */
metadata: DidMetadata;
/**
* Key Management System (KMS) used to manage the DIDs keys and sign data.
*
* Each DID method requires at least one key be present in the provided `keyManager`.
*/
keyManager: CryptoApi;
constructor({ uri, document, metadata, keyManager }: {
uri: string;
document: DidDocument;
metadata: DidMetadata;
keyManager: CryptoApi;
});
/**
* Converts a `BearerDid` object to a portable format containing the URI and verification methods
* associated with the DID.
*
* This method is useful when you need to represent the key material and metadata associated with
* a DID in format that can be used independently of the specific DID method implementation. It
* extracts both public and private keys from the DID's key manager and organizes them into a
* `PortableDid` structure.
*
* @remarks
* If the DID's key manager does not allow private keys to be exported, the `PortableDid` returned
* will not contain a `privateKeys` property. This enables the importing and exporting DIDs that
* use the same underlying KMS even if the KMS does not support exporting private keys. Examples
* include hardware security modules (HSMs) and cloud-based KMS services like AWS KMS.
*
* If the DID's key manager does support exporting private keys, the resulting `PortableDid` will
* include a `privateKeys` property which contains the same number of entries as there are
* verification methods as the DID document, each with its associated private key and the
* purpose(s) for which the key can be used (e.g., `authentication`, `assertionMethod`, etc.).
*
* @example
* ```ts
* // Assuming `did` is an instance of BearerDid
* const portableDid = await did.export();
* // portableDid now contains the DID URI, document, metadata, and optionally, private keys.
* ```
*
* @returns A `PortableDid` containing the URI, DID document, metadata, and optionally private
* keys associated with the `BearerDid`.
* @throws An error if the DID document does not contain any verification methods or the keys for
* any verification method are missing in the key manager.
*/
export(): Promise<PortableDid>;
/**
* Return a {@link Signer} that can be used to sign messages, credentials, or arbitrary data.
*
* If given, the `methodId` parameter is used to select a key from the verification methods
* present in the DID Document.
*
* If `methodID` is not given, the first verification method intended for signing claims is used.
*
* @param params - The parameters for the `getSigner` operation.
* @param params.methodId - ID of the verification method key that will be used for sign and
* verify operations. Optional.
* @returns An instantiated {@link Signer} that can be used to sign and verify data.
*/
getSigner(params?: {
methodId: string;
}): Promise<BearerDidSigner>;
/**
* Instantiates a {@link BearerDid} object from a given {@link PortableDid}.
*
* This method allows for the creation of a `BearerDid` object using a previously created DID's
* key material, DID document, and metadata.
*
* @example
* ```ts
* // Export an existing BearerDid to PortableDid format.
* const portableDid = await did.export();
* // Reconstruct a BearerDid object from the PortableDid.
* const did = await BearerDid.import({ portableDid });
* ```
*
* @param params - The parameters for the import operation.
* @param params.portableDid - The PortableDid object to import.
* @param params.keyManager - Optionally specify an external Key Management System (KMS) used to
* generate keys and sign data. If not given, a new
* {@link LocalKeyManager} instance will be created and
* used.
* @returns A Promise resolving to a `BearerDid` object representing the DID formed from the
* provided PortableDid.
* @throws An error if the PortableDid document does not contain any verification methods or the
* keys for any verification method are missing in the key manager.
*/
static import({ portableDid, keyManager }: {
keyManager?: CryptoApi & KeyImporterExporter<KmsImportKeyParams, KeyIdentifier, KmsExportKeyParams>;
portableDid: PortableDid;
}): Promise<BearerDid>;
}
//# sourceMappingURL=bearer-did.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"bearer-did.d.ts","sourceRoot":"","sources":["../../src/bearer-did.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,MAAM,EACN,SAAS,EACT,aAAa,EAEb,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EAEpB,MAAM,cAAc,CAAC;AAItB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAKxE;;;;;;;GAOG;AACH,MAAM,WAAW,eAAgB,SAAQ,MAAM;IAC7C;;;;;;;;;OASG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;;;;;;;;OAUG;IACH,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,qBAAa,SAAS;IACpB,4BAA4B;IAC5B,GAAG,EAAE,MAAM,CAAC;IAEZ;;;;OAIG;IACH,QAAQ,EAAE,WAAW,CAAC;IAEtB,gCAAgC;IAChC,QAAQ,EAAE,WAAW,CAAC;IAEtB;;;;OAIG;IACH,UAAU,EAAE,SAAS,CAAC;gBAEV,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE;QACnD,GAAG,EAAE,MAAM,CAAC;QACZ,QAAQ,EAAE,WAAW,CAAC;QACtB,QAAQ,EAAE,WAAW,CAAC;QACtB,UAAU,EAAE,SAAS,CAAA;KACtB;IAOD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+BG;IACU,MAAM,IAAI,OAAO,CAAC,WAAW,CAAC;IAoC3C;;;;;;;;;;;;OAYG;IACU,SAAS,CAAC,MAAM,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,eAAe,CAAC;IAwC/E;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;WACiB,MAAM,CAAC,EAAE,WAAW,EAAE,UAAkC,EAAE,EAAE;QAC9E,UAAU,CAAC,EAAE,SAAS,GAAG,mBAAmB,CAAC,kBAAkB,EAAE,aAAa,EAAE,kBAAkB,CAAC,CAAC;QACpG,WAAW,EAAE,WAAW,CAAC;KAC1B,GAAG,OAAO,CAAC,SAAS,CAAC;CAsCvB"}
+50
View File
@@ -0,0 +1,50 @@
/**
* A custom error class for DID-related errors.
*/
export declare class DidError extends Error {
code: DidErrorCode;
/**
* Constructs an instance of DidError, a custom error class for handling DID-related errors.
*
* @param code - A {@link DidErrorCode} representing the specific type of error encountered.
* @param message - A human-readable description of the error.
*/
constructor(code: DidErrorCode, message: string);
}
/**
* An enumeration of possible DID error codes.
*/
export declare enum DidErrorCode {
/** The DID supplied does not conform to valid syntax. */
InvalidDid = "invalidDid",
/** The supplied method name is not supported by the DID method and/or DID resolver implementation. */
MethodNotSupported = "methodNotSupported",
/** An unexpected error occurred during the requested DID operation. */
InternalError = "internalError",
/** The DID document supplied does not conform to valid syntax. */
InvalidDidDocument = "invalidDidDocument",
/** The byte length of a DID document does not match the expected value. */
InvalidDidDocumentLength = "invalidDidDocumentLength",
/** The DID URL supplied to the dereferencing function does not conform to valid syntax. */
InvalidDidUrl = "invalidDidUrl",
/** The given proof of a previous DID is invalid */
InvalidPreviousDidProof = "invalidPreviousDidProof",
/** An invalid public key is detected during a DID operation. */
InvalidPublicKey = "invalidPublicKey",
/** The byte length of a public key does not match the expected value. */
InvalidPublicKeyLength = "invalidPublicKeyLength",
/** An invalid public key type was detected during a DID operation. */
InvalidPublicKeyType = "invalidPublicKeyType",
/** Verification of a signature failed during a DID operation. */
InvalidSignature = "invalidSignature",
/** The DID resolver was unable to find the DID document resulting from the resolution request. */
NotFound = "notFound",
/**
* The representation requested via the `accept` input metadata property is not supported by the
* DID method and/or DID resolver implementation.
*/
RepresentationNotSupported = "representationNotSupported",
/** The type of a public key is not supported by the DID method and/or DID resolver implementation. */
UnsupportedPublicKeyType = "unsupportedPublicKeyType"
}
//# sourceMappingURL=did-error.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"did-error.d.ts","sourceRoot":"","sources":["../../src/did-error.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,QAAS,SAAQ,KAAK;IAOd,IAAI,EAAE,YAAY;IANrC;;;;;OAKG;gBACgB,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM;CAcvD;AAED;;GAEG;AACH,oBAAY,YAAY;IACtB,yDAAyD;IACzD,UAAU,eAAe;IAEzB,sGAAsG;IACtG,kBAAkB,uBAAuB;IAEzC,uEAAuE;IACvE,aAAa,kBAAkB;IAE/B,kEAAkE;IAClE,kBAAkB,uBAAuB;IAEzC,2EAA2E;IAC3E,wBAAwB,6BAA6B;IAErD,2FAA2F;IAC3F,aAAa,kBAAkB;IAE/B,mDAAmD;IACnD,uBAAuB,4BAA4B;IAEnD,gEAAgE;IAChE,gBAAgB,qBAAqB;IAErC,yEAAyE;IACzE,sBAAsB,2BAA2B;IAEjD,sEAAsE;IACtE,oBAAoB,yBAAyB;IAE7C,iEAAiE;IACjE,gBAAgB,qBAAqB;IAErC,kGAAkG;IAClG,QAAQ,aAAa;IAErB;;;OAGG;IACH,0BAA0B,+BAA+B;IAEzD,sGAAsG;IACtG,wBAAwB,6BAA6B;CACtD"}
+125
View File
@@ -0,0 +1,125 @@
/**
* The `Did` class represents a Decentralized Identifier (DID) Uniform Resource Identifier (URI).
*
* This class provides a method for parsing a DID URI string into its component parts, as well as a
* method for serializing a DID URI object into a string.
*
* A DID URI is composed of the following components:
* - scheme
* - method
* - id
* - path
* - query
* - fragment
* - params
*
* @see {@link https://www.w3.org/TR/did-core/#did-syntax | DID Core Specification, § DID Syntax}
*/
export declare class Did {
/** Regular expression pattern for matching the method component of a DID URI. */
static readonly METHOD_PATTERN = "([a-z0-9]+)";
/** Regular expression pattern for matching percent-encoded characters in a method identifier. */
static readonly PCT_ENCODED_PATTERN = "(?:%[0-9a-fA-F]{2})";
/** Regular expression pattern for matching the characters allowed in a method identifier. */
static readonly ID_CHAR_PATTERN: string;
/** Regular expression pattern for matching the method identifier component of a DID URI. */
static readonly METHOD_ID_PATTERN: string;
/** Regular expression pattern for matching the path component of a DID URI. */
static readonly PATH_PATTERN = "(/[^#?]*)?";
/** Regular expression pattern for matching the query component of a DID URI. */
static readonly QUERY_PATTERN = "([?][^#]*)?";
/** Regular expression pattern for matching the fragment component of a DID URI. */
static readonly FRAGMENT_PATTERN = "(#.*)?";
/** Regular expression pattern for matching all of the components of a DID URI. */
static readonly DID_URI_PATTERN: RegExp;
/**
* A string representation of the DID.
*
* A DID is a URI composed of three parts: the scheme `did:`, a method identifier, and a unique,
* method-specific identifier specified by the DID method.
*
* @example
* did:dht:h4d3ixkwt6q5a455tucw7j14jmqyghdtbr6cpiz6on5oxj5bpr3o
*/
uri: string;
/**
* The name of the DID method.
*
* Examples of DID method names are `dht`, `jwk`, and `web`, among others.
*/
method: string;
/**
* The DID method identifier.
*
* @example
* h4d3ixkwt6q5a455tucw7j14jmqyghdtbr6cpiz6on5oxj5bpr3o
*/
id: string;
/**
* Optional path component of the DID URI.
*
* @example
* did:web:tbd.website/path
*/
path?: string;
/**
* Optional query component of the DID URI.
*
* @example
* did:web:tbd.website?versionId=1
*/
query?: string;
/**
* Optional fragment component of the DID URI.
*
* @example
* did:web:tbd.website#key-1
*/
fragment?: string;
/**
* Optional query parameters in the DID URI.
*
* @example
* did:web:tbd.website?service=files&relativeRef=/whitepaper.pdf
*/
params?: Record<string, string>;
/**
* Constructs a new `Did` instance from individual components.
*
* @param params - An object containing the parameters to be included in the DID URI.
* @param params.method - The name of the DID method.
* @param params.id - The DID method identifier.
* @param params.path - Optional. The path component of the DID URI.
* @param params.query - Optional. The query component of the DID URI.
* @param params.fragment - Optional. The fragment component of the DID URI.
* @param params.params - Optional. The query parameters in the DID URI.
*/
constructor({ method, id, path, query, fragment, params }: {
method: string;
id: string;
path?: string;
query?: string;
fragment?: string;
params?: Record<string, string>;
});
/**
* Parses a DID URI string into its individual components.
*
* @example
* ```ts
* const did = Did.parse('did:example:123?service=agent&relativeRef=/credentials#degree');
*
* console.log(did.uri) // Output: 'did:example:123'
* console.log(did.method) // Output: 'example'
* console.log(did.id) // Output: '123'
* console.log(did.query) // Output: 'service=agent&relativeRef=/credentials'
* console.log(did.fragment) // Output: 'degree'
* console.log(did.params) // Output: { service: 'agent', relativeRef: '/credentials' }
* ```
*
* @params didUri - The DID URI string to be parsed.
* @returns A `Did` object representing the parsed DID URI, or `null` if the input string is not a valid DID URI.
*/
static parse(didUri: string): Did | null;
}
//# sourceMappingURL=did.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"did.d.ts","sourceRoot":"","sources":["../../src/did.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,GAAG;IACd,iFAAiF;IACjF,MAAM,CAAC,QAAQ,CAAC,cAAc,iBAAiB;IAC/C,iGAAiG;IACjG,MAAM,CAAC,QAAQ,CAAC,mBAAmB,yBAAyB;IAC5D,6FAA6F;IAC7F,MAAM,CAAC,QAAQ,CAAC,eAAe,SAAmD;IAClF,4FAA4F;IAC5F,MAAM,CAAC,QAAQ,CAAC,iBAAiB,SAA8D;IAC/F,+EAA+E;IAC/E,MAAM,CAAC,QAAQ,CAAC,YAAY,gBAAgB;IAC5C,gFAAgF;IAChF,MAAM,CAAC,QAAQ,CAAC,aAAa,iBAAiB;IAC9C,mFAAmF;IACnF,MAAM,CAAC,QAAQ,CAAC,gBAAgB,YAAY;IAC5C,kFAAkF;IAClF,MAAM,CAAC,QAAQ,CAAC,eAAe,SAE7B;IAEF;;;;;;;;OAQG;IACH,GAAG,EAAE,MAAM,CAAC;IAEZ;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;;;;OAKG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;;;;UAKM;IACN,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;;;UAKM;IACN,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;;;QAKI;IACJ,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEhC;;;;;;;;;;OAUG;gBACS,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE;QACzD,MAAM,EAAE,MAAM,CAAC;QACf,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAChC;IAUD;;;;;;;;;;;;;;;;;OAiBG;IACH,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI;CA4CzC"}
+18
View File
@@ -0,0 +1,18 @@
export * from './types/did-core.js';
export * from './types/did-resolution.js';
export type * from './types/multibase.js';
export type * from './types/portable-did.js';
export * from './did.js';
export * from './did-error.js';
export * from './bearer-did.js';
export * from './methods/did-dht.js';
export * from './methods/did-ion.js';
export * from './methods/did-jwk.js';
export * from './methods/did-key.js';
export * from './methods/did-method.js';
export * from './methods/did-web.js';
export * from './resolver/resolver-cache-level.js';
export * from './resolver/resolver-cache-noop.js';
export * from './resolver/universal-resolver.js';
export * as utils from './utils.js';
//# sourceMappingURL=index.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,mBAAmB,sBAAsB,CAAC;AAC1C,mBAAmB,yBAAyB,CAAC;AAE7C,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAEhC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AAErC,cAAc,oCAAoC,CAAC;AACnD,cAAc,mCAAmC,CAAC;AAClD,cAAc,kCAAkC,CAAC;AAEjD,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC"}
+682
View File
@@ -0,0 +1,682 @@
import type { Packet, TxtData } from '@dnsquery/dns-packet';
import type { Jwk, Signer, CryptoApi, KeyIdentifier, KmsExportKeyParams, KmsImportKeyParams, KeyImporterExporter, AsymmetricKeyConverter } from '@web5/crypto';
import type { DidMetadata, PortableDid } from '../types/portable-did.js';
import type { DidCreateOptions, DidCreateVerificationMethod, DidRegistrationResult } from './did-method.js';
import type { DidService, DidDocument, DidResolutionResult, DidResolutionOptions, DidVerificationMethod } from '../types/did-core.js';
import { DidMethod } from './did-method.js';
import { BearerDid } from '../bearer-did.js';
/**
* Represents a BEP44 message, which is used for storing and retrieving data in the Mainline DHT
* network.
*
* A BEP44 message is used primarily in the context of the DID DHT method for publishing and
* resolving DID documents in the DHT network. This type encapsulates the data structure required
* for such operations in accordance with BEP44.
*
* @see {@link https://www.bittorrent.org/beps/bep_0044.html | BEP44}
*/
export interface Bep44Message {
/**
* The public key bytes of the Identity Key, which serves as the identifier in the DHT network for
* the corresponding BEP44 message.
*/
k: Uint8Array;
/**
* The sequence number of the message, used to ensure the latest version of the data is retrieved
* and updated. It's a monotonically increasing number.
*/
seq: number;
/**
* The signature of the message, ensuring the authenticity and integrity of the data. It's
* computed over the bencoded sequence number and value.
*/
sig: Uint8Array;
/**
* The actual data being stored or retrieved from the DHT network, typically encoded in a format
* suitable for DNS packet representation of a DID Document.
*/
v: Uint8Array;
}
/**
* Options for creating a Decentralized Identifier (DID) using the DID DHT method.
*/
export interface DidDhtCreateOptions<TKms> extends DidCreateOptions<TKms> {
/**
* Optionally specify that the DID Subject is also identified by one or more other DIDs or URIs.
*
* A DID subject can have multiple identifiers for different purposes, or at different times.
* The assertion that two or more DIDs (or other types of URI) refer to the same DID subject can
* be made using the `alsoKnownAs` property.
*
* @see {@link https://www.w3.org/TR/did-core/#also-known-as | DID Core Specification, § Also Known As}
*
* @example
* ```ts
* const did = await DidDht.create({
* options: {
* alsoKnownAs: 'did:example:123'
* };
* ```
*/
alsoKnownAs?: string[];
/**
* Optionally specify which DID (or DIDs) is authorized to make changes to the DID document.
*
* A DID controller is an entity that is authorized to make changes to a DID document. Typically,
* only the DID Subject (i.e., the value of `id` property in the DID document) is authoritative.
* However, another DID (or DIDs) can be specified as the DID controller, and when doing so, any
* verification methods contained in the DID document for the other DID should be accepted as
* authoritative. In other words, proofs created by the controller DID should be considered
* equivalent to proofs created by the DID Subject.
*
* @see {@link https://www.w3.org/TR/did-core/#did-controller | DID Core Specification, § DID Controller}
*
* @example
* ```ts
* const did = await DidDht.create({
* options: {
* controller: 'did:example:123'
* };
* ```
*/
controllers?: string | string[];
/**
* Optional. The URI of a server involved in executing DID method operations. In the context of
* DID creation, the endpoint is expected to be a DID DHT Gateway or Pkarr relay. If not
* specified, a default gateway node is used.
*/
gatewayUri?: string;
/**
* Optional. Determines whether the created DID should be published to the DHT network.
*
* If set to `true` or omitted, the DID is publicly discoverable. If `false`, the DID is not
* published and cannot be resolved by others. By default, newly created DIDs are published.
*
* @see {@link https://did-dht.com | DID DHT Method Specification}
*
* @example
* ```ts
* const did = await DidDht.create({
* options: {
* publish: false
* };
* ```
*/
publish?: boolean;
/**
* Optional. An array of service endpoints associated with the DID.
*
* Services are used in DID documents to express ways of communicating with the DID subject or
* associated entities. A service can be any type of service the DID subject wants to advertise,
* including decentralized identity management services for further discovery, authentication,
* authorization, or interaction.
*
* @see {@link https://www.w3.org/TR/did-core/#services | DID Core Specification, § Services}
*
* @example
* ```ts
* const did = await DidDht.create({
* options: {
* services: [
* {
* id: 'did:dht:i9xkp8ddcbcg8jwq54ox699wuzxyifsqx4jru45zodqu453ksz6y#dwn',
* type: 'DecentralizedWebNode',
* serviceEndpoint: ['https://example.com/dwn1', 'https://example/dwn2']
* }
* ]
* };
* ```
*/
services?: DidService[];
/**
* Optionally specify one or more registered DID DHT types to make the DID discovereable.
*
* Type indexing is an OPTIONAL feature that enables DIDs to become discoverable. DIDs that wish
* to be discoverable and resolveable by type can include one or more types when publishing their
* DID document to a DID DHT Gateway.
*
* The registered DID types are published in the {@link https://did-dht.com/registry/index.html#indexed-types | DID DHT Registry}.
*/
types?: (DidDhtRegisteredDidType | keyof typeof DidDhtRegisteredDidType)[];
/**
* Optional. An array of verification methods to be included in the DID document.
*
* By default, a newly created DID DHT document will contain a single Ed25519 verification method,
* also known as the {@link https://did-dht.com/#term:identity-key | Identity Key}. Additional
* verification methods can be added to the DID document using the `verificationMethods` property.
*
* @see {@link https://www.w3.org/TR/did-core/#verification-methods | DID Core Specification, § Verification Methods}
*
* @example
* ```ts
* const did = await DidDht.create({
* options: {
* verificationMethods: [
* {
* algorithm: 'Ed25519',
* purposes: ['authentication', 'assertionMethod']
* },
* {
* algorithm: 'Ed25519',
* id: 'dwn-sig',
* purposes: ['authentication', 'assertionMethod']
* }
* ]
* };
* ```
*/
verificationMethods?: DidCreateVerificationMethod<TKms>[];
}
/**
* Proof to used to construct the `_prv._did.` DNS record as described in https://did-dht.com/#rotation to link a DID to a previous DID.
*/
export type PreviousDidProof = {
/** The previous DID. */
previousDid: string;
/** The signature signed using the private Identity Key of the previous DID in Base64URL format. */
signature: string;
};
/**
* Represents an optional extension to a DID Documents DNS packet representation exposed as a
* type index.
*
* Type indexing is an OPTIONAL feature that enables DIDs to become discoverable. DIDs that wish to
* be discoverable and resolveable by type can include one or more types when publishing their DID
* document to a DID DHT Gateway.
*
* The registered DID types are published in the {@link https://did-dht.com/registry/index.html#indexed-types | DID DHT Registry}.
*/
export declare enum DidDhtRegisteredDidType {
/**
* Type 0 is reserved for DIDs that do not wish to associate themselves with a specific type but
* wish to make themselves discoverable.
*/
Discoverable = 0,
/**
* Organization
* @see {@link https://schema.org/Organization | schema definition}
*/
Organization = 1,
/**
* Government Organization
* @see {@link https://schema.org/GovernmentOrganization | schema definition}
*/
Government = 2,
/**
* Corporation
* @see {@link https://schema.org/Corporation | schema definition}
*/
Corporation = 3,
/**
* Corporation
* @see {@link https://schema.org/Corporation | schema definition}
*/
LocalBusiness = 4,
/**
* Software Package
* @see {@link https://schema.org/SoftwareSourceCode | schema definition}
*/
SoftwarePackage = 5,
/**
* Web App
* @see {@link https://schema.org/WebApplication | schema definition}
*/
WebApp = 6,
/**
* Financial Institution
* @see {@link https://schema.org/FinancialService | schema definition}
*/
FinancialInstitution = 7
}
/**
* Enumerates the types of keys that can be used in a DID DHT document.
*
* The DID DHT method supports various cryptographic key types. These key types are essential for
* the creation and management of DIDs and their associated cryptographic operations like signing
* and encryption. The registered key types are published in the DID DHT Registry and each is
* assigned a unique numerical value for use by client and gateway implementations.
*
* The registered key types are published in the {@link https://did-dht.com/registry/index.html#key-type-index | DID DHT Registry}.
*/
export declare enum DidDhtRegisteredKeyType {
/**
* Ed25519: A public-key signature system using the EdDSA (Edwards-curve Digital Signature
* Algorithm) and Curve25519.
*/
Ed25519 = 0,
/**
* secp256k1: A cryptographic curve used for digital signatures in a range of decentralized
* systems.
*/
secp256k1 = 1,
/**
* secp256r1: Also known as P-256 or prime256v1, this curve is used for cryptographic operations
* and is widely supported in various cryptographic libraries and standards.
*/
secp256r1 = 2,
/**
* X25519: A public key used for Diffie-Hellman key exchange using Curve25519.
*/
X25519 = 3
}
/**
* Maps {@link https://www.w3.org/TR/did-core/#verification-relationships | DID Core Verification Relationship}
* values to the corresponding record name in the DNS packet representation of a DHT DID document.
*/
export declare enum DidDhtVerificationRelationship {
/**
* Specifies how the DID subject is expected to be authenticated.
*/
authentication = "auth",
/**
* Specifies how the DID subject is expected to express claims, such as for issuing Verifiable
* Credentials.
*/
assertionMethod = "asm",
/**
* Specifies a mechanism used by the DID subject to delegate a cryptographic capability to another
* party
*/
capabilityDelegation = "del",
/**
* Specifies a verification method used by the DID subject to invoke a cryptographic capability.
*/
capabilityInvocation = "inv",
/**
* Specifies how an entity can generate encryption material to communicate confidentially with the
* DID subject.
*/
keyAgreement = "agm"
}
/**
* The `DidDht` class provides an implementation of the `did:dht` DID method.
*
* Features:
* - DID Creation: Create new `did:dht` DIDs.
* - DID Key Management: Instantiate a DID object from an existing verification method keys or
* or a key in a Key Management System (KMS). If supported by the KMS, a DID's
* key can be exported to a portable DID format.
* - DID Resolution: Resolve a `did:dht` to its corresponding DID Document stored in the DHT network.
* - Signature Operations: Sign and verify messages using keys associated with a DID.
*
* @remarks
* The `did:dht` method leverages the distributed nature of the Mainline DHT network for
* decentralized identity management. This method allows DIDs to be resolved without relying on
* centralized registries or ledgers, enhancing privacy and control for users. The DID Document is
* stored and retrieved from the DHT network, and the method includes optional mechanisms for
* discovering DIDs by type.
*
* The DID URI in the `did:dht` method includes a method-specific identifier called the Identity Key
* which corresponds to the DID's entry in the DHT network. The Identity Key required to make
* changes to the DID Document since Mainline DHT nodes validate the signature of each message
* before storing the value in the DHT.
*
* @see {@link https://did-dht.com | DID DHT Method Specification}
*
* @example
* ```ts
* // DID Creation
* const did = await DidDht.create();
*
* // DID Creation with a KMS
* const keyManager = new LocalKeyManager();
* const did = await DidDht.create({ keyManager });
*
* // DID Resolution
* const resolutionResult = await DidDht.resolve({ did: did.uri });
*
* // Signature Operations
* const signer = await did.getSigner();
* const signature = await signer.sign({ data: new TextEncoder().encode('Message') });
* const isValid = await signer.verify({ data: new TextEncoder().encode('Message'), signature });
*
* // Import / Export
*
* // Export a BearerDid object to the PortableDid format.
* const portableDid = await did.export();
*
* // Reconstruct a BearerDid object from a PortableDid
* const did = await DidDht.import(portableDid);
* ```
*/
export declare class DidDht extends DidMethod {
/**
* Name of the DID method, as defined in the DID DHT specification.
*/
static methodName: string;
/**
* Creates a new DID using the `did:dht` method formed from a newly generated key.
*
* @remarks
* The DID URI is formed by z-base-32 encoding the Identity Key public key and prefixing with
* `did:dht:`.
*
* Notes:
* - If no `options` are given, by default a new Ed25519 key will be generated which serves as the
* Identity Key.
*
* @example
* ```ts
* // DID Creation
* const did = await DidDht.create();
*
* // DID Creation with a KMS
* const keyManager = new LocalKeyManager();
* const did = await DidDht.create({ keyManager });
* ```
*
* @param params - The parameters for the create operation.
* @param params.keyManager - Optionally specify a Key Management System (KMS) used to generate
* keys and sign data.
* @param params.options - Optional parameters that can be specified when creating a new DID.
* @returns A Promise resolving to a {@link BearerDid} object representing the new DID.
*/
static create<TKms extends CryptoApi | undefined = undefined>({ keyManager, options }?: {
keyManager?: TKms;
options?: DidDhtCreateOptions<TKms>;
}): Promise<BearerDid>;
/**
* Instantiates a {@link BearerDid} object for the DID DHT method from a given {@link PortableDid}.
*
* This method allows for the creation of a `BearerDid` object using a previously created DID's
* key material, DID document, and metadata.
*
* @example
* ```ts
* // Export an existing BearerDid to PortableDid format.
* const portableDid = await did.export();
* // Reconstruct a BearerDid object from the PortableDid.
* const did = await DidDht.import({ portableDid });
* ```
*
* @param params - The parameters for the import operation.
* @param params.portableDid - The PortableDid object to import.
* @param params.keyManager - Optionally specify an external Key Management System (KMS) used to
* generate keys and sign data. If not given, a new
* {@link LocalKeyManager} instance will be created and
* used.
* @returns A Promise resolving to a `BearerDid` object representing the DID formed from the
* provided PortableDid.
* @throws An error if the PortableDid document does not contain any verification methods, lacks
* an Identity Key, or the keys for any verification method are missing in the key
* manager.
*/
static import({ portableDid, keyManager }: {
keyManager?: CryptoApi & KeyImporterExporter<KmsImportKeyParams, KeyIdentifier, KmsExportKeyParams>;
portableDid: PortableDid;
}): Promise<BearerDid>;
/**
* Given the W3C DID Document of a `did:dht` DID, return the verification method that will be used
* for signing messages and credentials. If given, the `methodId` parameter is used to select the
* verification method. If not given, the Identity Key's verification method with an ID fragment
* of '#0' is used.
*
* @param params - The parameters for the `getSigningMethod` operation.
* @param params.didDocument - DID Document to get the verification method from.
* @param params.methodId - ID of the verification method to use for signing.
* @returns Verification method to use for signing.
*/
static getSigningMethod({ didDocument, methodId }: {
didDocument: DidDocument;
methodId?: string;
}): Promise<DidVerificationMethod>;
/**
* Publishes a DID to the DHT, making it publicly discoverable and resolvable.
*
* This method handles the publication of a DID Document associated with a `did:dht` DID to the
* Mainline DHT network. The publication process involves storing the DID Document in Mainline DHT
* via a Pkarr relay server.
*
* @remarks
* - This method is typically invoked automatically during the creation of a new DID unless the
* `publish` option is set to `false`.
* - For existing, unpublished DIDs, it can be used to publish the DID Document to Mainline DHT.
* - The method relies on the specified Pkarr relay server to interface with the DHT network.
*
* @example
* ```ts
* // Generate a new DID and keys but explicitly disable publishing.
* const did = await DidDht.create({ options: { publish: false } });
* // Publish the DID to the DHT.
* const registrationResult = await DidDht.publish({ did });
* // `registrationResult.didDocumentMetadata.published` is true if the DID was successfully published.
* ```
*
* @param params - The parameters for the `publish` operation.
* @param params.did - The `BearerDid` object representing the DID to be published.
* @param params.gatewayUri - Optional. The URI of a server involved in executing DID method
* operations. In the context of publishing, the endpoint is expected
* to be a DID DHT Gateway or Pkarr Relay. If not specified, a default
* gateway node is used.
* @returns A promise that resolves to a {@link DidRegistrationResult} object that contains
* the result of registering the DID with a DID DHT Gateway or Pkarr relay.
*/
static publish({ did, gatewayUri }: {
did: BearerDid;
gatewayUri?: string;
}): Promise<DidRegistrationResult>;
/**
* Resolves a `did:dht` identifier to its corresponding DID document.
*
* This method performs the resolution of a `did:dht` DID, retrieving its DID Document from the
* Mainline DHT network. The process involves querying the DHT network via a Pkarr relay server to
* retrieve the DID Document that corresponds to the given DID identifier.
*
* @remarks
* - If a `gatewayUri` option is not specified, a default Pkarr relay is used to access the DHT
* network.
* - It decodes the DID identifier and retrieves the associated DID Document and metadata.
* - In case of resolution failure, appropriate error information is returned.
*
* @example
* ```ts
* const resolutionResult = await DidDht.resolve('did:dht:example');
* ```
*
* @param didUri - The DID to be resolved.
* @param options - Optional parameters for resolving the DID. Unused by this DID method.
* @returns A Promise resolving to a {@link DidResolutionResult} object representing the result of
* the resolution.
*/
static resolve(didUri: string, options?: DidResolutionOptions): Promise<DidResolutionResult>;
}
/**
* The `DidDhtDocument` class provides functionality for interacting with the DID document stored in
* Mainline DHT in support of DID DHT method create, resolve, update, and deactivate operations.
*
* This class includes methods for retrieving and publishing DID documents to and from the DHT,
* using DNS packet encoding and DID DHT Gateway or Pkarr Relay servers.
*/
export declare class DidDhtDocument {
/**
* Retrieves a DID document and its metadata from the DHT network.
*
* @param params - The parameters for the get operation.
* @param params.didUri - The DID URI containing the Identity Key.
* @param params.gatewayUri - The DID DHT Gateway or Pkarr Relay URI.
* @returns A Promise resolving to a {@link DidResolutionResult} object containing the DID
* document and its metadata.
*/
static get({ didUri, gatewayUri }: {
didUri: string;
gatewayUri: string;
}): Promise<DidResolutionResult>;
/**
* Publishes a DID document to the DHT network.
*
* @param params - The parameters to use when publishing the DID document to the DHT network.
* @param params.did - The DID object whose DID document will be published.
* @param params.gatewayUri - The DID DHT Gateway or Pkarr Relay URI.
* @returns A promise that resolves to a {@link DidRegistrationResult} object that contains
* the result of registering the DID with a DID DHT Gateway or Pkarr relay.
*/
static put({ did, gatewayUri }: {
did: BearerDid;
gatewayUri: string;
}): Promise<DidRegistrationResult>;
/**
* Retrieves a signed BEP44 message from a DID DHT Gateway or Pkarr Relay server.
*
* @see {@link https://github.com/Nuhvi/pkarr/blob/main/design/relays.md | Pkarr Relay design}
*
* @param params
* @param params.gatewayUri - The DID DHT Gateway or Pkarr Relay URI.
* @param params.publicKeyBytes - The public key bytes of the Identity Key, z-base-32 encoded.
* @returns A promise resolving to a BEP44 message containing the signed DNS packet.
*/
private static pkarrGet;
/**
* Publishes a signed BEP44 message to a DID DHT Gateway or Pkarr Relay server.
*
* @see {@link https://github.com/Nuhvi/pkarr/blob/main/design/relays.md | Pkarr Relay design}
*
* @param params - The parameters to use when publishing a signed BEP44 message to a Pkarr relay server.
* @param params.gatewayUri - The DID DHT Gateway or Pkarr Relay URI.
* @param params.bep44Message - The BEP44 message to be published, containing the signed DNS packet.
* @returns A promise resolving to `true` if the message was successfully published, otherwise `false`.
*/
private static pkarrPut;
/**
* Converts a DNS packet to a DID document according to the DID DHT specification.
*
* @see {@link https://did-dht.com/#dids-as-dns-records | DID DHT Specification, § DIDs as DNS Records}
*
* @param params - The parameters to use when converting a DNS packet to a DID document.
* @param params.didUri - The DID URI of the DID document.
* @param params.dnsPacket - The DNS packet to convert to a DID document.
* @returns A Promise resolving to a {@link DidResolutionResult} object containing the DID
* document and its metadata.
*/
static fromDnsPacket({ didUri, dnsPacket }: {
didUri: string;
dnsPacket: Packet;
}): Promise<DidResolutionResult>;
/**
* Converts a DID document to a DNS packet according to the DID DHT specification.
*
* @see {@link https://did-dht.com/#dids-as-dns-records | DID DHT Specification, § DIDs as DNS Records}
*
* @param params - The parameters to use when converting a DID document to a DNS packet.
* @param params.didDocument - The DID document to convert to a DNS packet.
* @param params.didMetadata - The DID metadata to include in the DNS packet.
* @param params.authoritativeGatewayUris - The URIs of the Authoritative Gateways to generate NS records from.
* @param params.previousDidProof - The signature proof that this DID is linked to the given previous DID.
* @returns A promise that resolves to a DNS packet.
*/
static toDnsPacket({ didDocument, didMetadata, authoritativeGatewayUris, previousDidProof }: {
didDocument: DidDocument;
didMetadata: DidMetadata;
authoritativeGatewayUris?: string[];
previousDidProof?: PreviousDidProof;
}): Promise<Packet>;
/**
* Gets the unique portion of the DID identifier after the last `:` character.
* e.g. `did:dht:example` -> `example`
*
* @param did - The DID to extract the unique suffix from.
*/
private static getUniqueDidSuffix;
}
/**
* The `DidDhtUtils` class provides utility functions to support operations in the DID DHT method.
* This includes functions for creating and parsing BEP44 messages, handling identity keys, and
* converting between different formats and representations.
*/
export declare class DidDhtUtils {
/**
* Creates a BEP44 put message, which is used to publish a DID document to the DHT network.
*
* @param params - The parameters to use when creating the BEP44 put message
* @param params.dnsPacket - The DNS packet to encode in the BEP44 message.
* @param params.publicKeyBytes - The public key bytes of the Identity Key.
* @param params.signer - Signer that can sign and verify data using the Identity Key.
* @returns A promise that resolves to a BEP44 put message.
*/
static createBep44PutMessage({ dnsPacket, publicKeyBytes, signer }: {
dnsPacket: Packet;
publicKeyBytes: Uint8Array;
signer: Signer;
}): Promise<Bep44Message>;
/**
* Converts a DID URI to a JSON Web Key (JWK) representing the Identity Key.
*
* @param params - The parameters to use for the conversion.
* @param params.didUri - The DID URI containing the Identity Key.
* @returns A promise that resolves to a JWK representing the Identity Key.
*/
static identifierToIdentityKey({ didUri }: {
didUri: string;
}): Promise<Jwk>;
/**
* Converts a DID URI to the byte array representation of the Identity Key.
*
* @param params - The parameters to use for the conversion.
* @param params.didUri - The DID URI containing the Identity Key.
* @returns A byte array representation of the Identity Key.
*/
static identifierToIdentityKeyBytes({ didUri }: {
didUri: string;
}): Uint8Array;
/**
* Encodes a DID DHT Identity Key into a DID identifier.
*
* This method first z-base-32 encodes the Identity Key. The resulting string is prefixed with
* `did:dht:` to form the DID identifier.
*
* @param params - The parameters to use for the conversion.
* @param params.identityKey The Identity Key from which the DID identifier is computed.
* @returns A promise that resolves to a string containing the DID identifier.
*/
static identityKeyToIdentifier({ identityKey }: {
identityKey: Jwk;
}): Promise<string>;
/**
* Returns the appropriate key converter for the specified cryptographic curve.
*
* @param curve - The cryptographic curve to use for the key conversion.
* @returns An `AsymmetricKeyConverter` for the specified curve.
*/
static keyConverter(curve: string): AsymmetricKeyConverter;
/**
* Parses and verifies a BEP44 Get message, converting it to a DNS packet.
*
* @param params - The parameters to use when verifying and parsing the BEP44 Get response message.
* @param params.bep44Message - The BEP44 message to verify and parse.
* @returns A promise that resolves to a DNS packet.
*/
static parseBep44GetMessage({ bep44Message }: {
bep44Message: Bep44Message;
}): Promise<Packet>;
/**
* Decodes and parses the data value of a DNS TXT record into a key-value object.
*
* @param txtData - The data value of a DNS TXT record.
* @returns An object containing the key/value pairs of the TXT record data.
*/
static parseTxtDataToObject(txtData: TxtData): Record<string, string>;
/**
* Decodes and parses the data value of a DNS TXT record into a string.
*
* @param txtData - The data value of a DNS TXT record.
* @returns A string representation of the TXT record data.
*/
static parseTxtDataToString(txtData: TxtData): string;
/**
* Validates the proof of previous DID given.
*
* @param params - The parameters to validate the previous DID proof.
* @param params.newDid - The new DID that the previous DID is linking to.
* @param params.previousDidProof - The proof of the previous DID, containing the previous DID and signature signed by the previous DID.
*/
static validatePreviousDidProof({ newDid, previousDidProof }: {
newDid: string;
previousDidProof: PreviousDidProof;
}): Promise<void>;
/**
* Splits a string into chunks of length 255 if the string exceeds length 255.
* @param data - The string to split into chunks.
* @returns The original string if its length is less than or equal to 255, otherwise an array of chunked strings.
*/
static chunkDataIfNeeded(data: string): string | string[];
}
//# sourceMappingURL=did-dht.d.ts.map
File diff suppressed because one or more lines are too long
+492
View File
@@ -0,0 +1,492 @@
import type { CryptoApi, Jwk, KeyIdentifier, KeyImporterExporter, KmsExportKeyParams, KmsImportKeyParams } from '@web5/crypto';
import type { IonDocumentModel } from '@decentralized-identity/ion-sdk';
import type { PortableDid } from '../types/portable-did.js';
import type { DidCreateOptions, DidCreateVerificationMethod, DidRegistrationResult } from '../methods/did-method.js';
import type { DidService, DidDocument, DidResolutionResult, DidResolutionOptions, DidVerificationMethod, DidVerificationRelationship } from '../types/did-core.js';
import { BearerDid } from '../bearer-did.js';
import { DidMethod } from '../methods/did-method.js';
/**
* Options for creating a Decentralized Identifier (DID) using the DID ION method.
*/
export interface DidIonCreateOptions<TKms> extends DidCreateOptions<TKms> {
/**
* Optional. The URI of a server involved in executing DID method operations. In the context of
* DID creation, the endpoint is expected to be a Sidetree node. If not specified, a default
* gateway node is used.
*/
gatewayUri?: string;
/**
* Optional. Determines whether the created DID should be published to a Sidetree node.
*
* If set to `true` or omitted, the DID is publicly discoverable. If `false`, the DID is not
* published and cannot be resolved by others. By default, newly created DIDs are published.
*
* @see {@link https://identity.foundation/sidetree/spec/#create | Sidetree Protocol Specification, § Create}
*
* @example
* ```ts
* const did = await DidIon.create({
* options: {
* publish: false
* };
* ```
*/
publish?: boolean;
/**
* Optional. An array of service endpoints associated with the DID.
*
* Services are used in DID documents to express ways of communicating with the DID subject or
* associated entities. A service can be any type of service the DID subject wants to advertise,
* including decentralized identity management services for further discovery, authentication,
* authorization, or interaction.
*
* @see {@link https://www.w3.org/TR/did-core/#services | DID Core Specification, § Services}
*
* @example
* ```ts
* const did = await DidIon.create({
* options: {
* services: [
* {
* id: 'dwn',
* type: 'DecentralizedWebNode',
* serviceEndpoint: ['https://example.com/dwn1', 'https://example/dwn2']
* }
* ]
* };
* ```
*/
services?: DidService[];
/**
* Optional. An array of verification methods to be included in the DID document.
*
* By default, a newly created DID ION document will contain a single Ed25519 verification method.
* Additional verification methods can be added to the DID document using the
* `verificationMethods` property.
*
* @see {@link https://www.w3.org/TR/did-core/#verification-methods | DID Core Specification, § Verification Methods}
*
* @example
* ```ts
* const did = await DidIon.create({
* options: {
* verificationMethods: [
* {
* algorithm: 'Ed25519',
* purposes: ['authentication', 'assertionMethod']
* },
* {
* algorithm: 'Ed25519',
* id: 'dwn-sig',
* purposes: ['authentication', 'assertionMethod']
* }
* ]
* };
* ```
*/
verificationMethods?: DidCreateVerificationMethod<TKms>[];
}
/**
* Represents the request model for managing DID documents within the ION network, according to the
* Sidetree protocol specification.
*/
export interface DidIonCreateRequest {
/** The type of operation to perform, which is always 'create' for a Create Operation. */
type: 'create';
/** Contains properties related to the initial state of the DID document. */
suffixData: {
/** A hash of the `delta` object, representing the initial changes to the DID document. */
deltaHash: string;
/** A commitment value used for future recovery operations, hashed for security. */
recoveryCommitment: string;
};
/** Details the changes to be applied to the DID document in this operation. */
delta: {
/** A commitment value used for the next update operation, hashed for security. */
updateCommitment: string;
/** An array of patch objects specifying the modifications to apply to the DID document. */
patches: {
/** The type of modification to perform (e.g., adding or removing public keys or service
* endpoints). */
action: string;
/** The document state or partial state to apply with this patch. */
document: IonDocumentModel;
}[];
};
}
/**
* Represents a {@link DidVerificationMethod | DID verification method} in the context of DID ION
* create, update, deactivate, and resolve operations.
*
* Unlike the DID Core standard {@link DidVerificationMethod} interface, this type is specific to
* the ION method operations and only includes the `id`, `publicKeyJwk`, and `purposes` properties:
* - The `id` property is optional and specifies the identifier fragment of the verification method.
* - The `publicKeyJwk` property is required and represents the public key in JWK format.
* - The `purposes` property is required and specifies the purposes for which the verification
* method can be used.
*
* @example
* ```ts
* const verificationMethod: DidIonVerificationMethod = {
* id : 'sig',
* publicKeyJwk : {
* kty : 'OKP',
* crv : 'Ed25519',
* x : 'o40shZrsco-CfEqk6mFsXfcP94ly3Az3gm84PzAUsXo',
* kid : 'BDp0xim82GswlxnPV8TPtBdUw80wkGIF8gjFbw1x5iQ',
* },
* purposes: ['authentication', 'assertionMethod']
* };
* ```
*/
export interface DidIonVerificationMethod {
/**
* Optionally specify the identifier fragment of the verification method.
*
* If not specified, the method's ID will be generated from the key's ID or thumbprint.
*
* @example
* ```ts
* const verificationMethod: DidIonVerificationMethod = {
* id: 'sig',
* ...
* };
* ```
*/
id?: string;
/**
* A public key in JWK format.
*
* A JSON Web Key (JWK) that conforms to {@link https://datatracker.ietf.org/doc/html/rfc7517 | RFC 7517}.
*
* @example
* ```ts
* const verificationMethod: DidIonVerificationMethod = {
* publicKeyJwk: {
* kty : "OKP",
* crv : "X25519",
* x : "7XdJtNmJ9pV_O_3mxWdn6YjiHJ-HhNkdYQARzVU_mwY",
* kid : "xtsuKULPh6VN9fuJMRwj66cDfQyLaxuXHkMlmAe_v6I"
* },
* ...
* };
* ```
*/
publicKeyJwk: Jwk;
/**
* Specify the purposes for which a verification method is intended to be used in a DID document.
*
* The `purposes` property defines the specific
* {@link DidVerificationRelationship | verification relationships} between the DID subject and
* the verification method. This enables the verification method to be utilized for distinct
* actions such as authentication, assertion, key agreement, capability delegation, and others. It
* is important for verifiers to recognize that a verification method must be associated with the
* relevant purpose in the DID document to be valid for that specific use case.
*
* @example
* ```ts
* const verificationMethod: DidIonVerificationMethod = {
* purposes: ['authentication', 'assertionMethod'],
* ...
* };
* ```
*/
purposes: (DidVerificationRelationship | keyof typeof DidVerificationRelationship)[];
}
/**
* `IonPortableDid` interface extends the {@link PortableDid} interface.
*
* It represents a Decentralized Identifier (DID) that is portable and can be used across different
* domains, including the ION specific recovery and update keys.
*/
export interface IonPortableDid extends PortableDid {
/** The JSON Web Key (JWK) used for recovery purposes. */
recoveryKey: Jwk;
/** The JSON Web Key (JWK) used for updating the DID. */
updateKey: Jwk;
}
/**
* Enumerates the types of keys that can be used in a DID ION document.
*
* The DID ION method supports various cryptographic key types. These key types are essential for
* the creation and management of DIDs and their associated cryptographic operations like signing
* and encryption.
*/
export declare enum DidIonRegisteredKeyType {
/**
* Ed25519: A public-key signature system using the EdDSA (Edwards-curve Digital Signature
* Algorithm) and Curve25519.
*/
Ed25519 = "Ed25519",
/**
* secp256k1: A cryptographic curve used for digital signatures in a range of decentralized
* systems.
*/
secp256k1 = "secp256k1",
/**
* secp256r1: Also known as P-256 or prime256v1, this curve is used for cryptographic operations
* and is widely supported in various cryptographic libraries and standards.
*/
secp256r1 = "secp256r1",
/**
* X25519: A Diffie-Hellman key exchange algorithm using Curve25519.
*/
X25519 = "X25519"
}
/**
* The `DidIon` class provides an implementation of the `did:ion` DID method.
*
* Features:
* - DID Creation: Create new `did:ion` DIDs.
* - DID Key Management: Instantiate a DID object from an existing key in a Key Management System
* (KMS). If supported by the KMS, a DID's key can be exported to a portable
* DID format.
* - DID Resolution: Resolve a `did:ion` to its corresponding DID Document stored in the Sidetree
* network.
* - Signature Operations: Sign and verify messages using keys associated with a DID.
*
* @see {@link https://identity.foundation/sidetree/spec/ | Sidetree Protocol Specification}
* @see {@link https://github.com/decentralized-identity/ion/blob/master/docs/design.md | ION Design Document}
*
* @example
* ```ts
* // DID Creation
* const did = await DidIon.create();
*
* // DID Creation with a KMS
* const keyManager = new LocalKeyManager();
* const did = await DidIon.create({ keyManager });
*
* // DID Resolution
* const resolutionResult = await DidIon.resolve({ did: did.uri });
*
* // Signature Operations
* const signer = await did.getSigner();
* const signature = await signer.sign({ data: new TextEncoder().encode('Message') });
* const isValid = await signer.verify({ data: new TextEncoder().encode('Message'), signature });
*
* // Key Management
*
* // Instantiate a DID object for a published DID with existing keys in a KMS
* const did = await DidIon.fromKeyManager({
* didUri: 'did:ion:EiAzB7K-xDIKc1csXo5HX2eNBoemK9feNhL3cKwfukYOug',
* keyManager
* });
*
* // Convert a DID object to a portable format
* const portableDid = await DidIon.toKeys({ did });
* ```
*/
export declare class DidIon extends DidMethod {
/**
* Name of the DID method, as defined in the DID ION specification.
*/
static methodName: string;
/**
* Creates a new DID using the `did:ion` method formed from a newly generated key.
*
* Notes:
* - If no `options` are given, by default a new Ed25519 key will be generated.
*
* @example
* ```ts
* // DID Creation
* const did = await DidIon.create();
*
* // DID Creation with a KMS
* const keyManager = new LocalKeyManager();
* const did = await DidIon.create({ keyManager });
* ```
*
* @param params - The parameters for the create operation.
* @param params.keyManager - Optionally specify a Key Management System (KMS) used to generate
* keys and sign data.
* @param params.options - Optional parameters that can be specified when creating a new DID.
* @returns A Promise resolving to a {@link BearerDid} object representing the new DID.
*/
static create<TKms extends CryptoApi | undefined = undefined>({ keyManager, options }?: {
keyManager?: TKms;
options?: DidIonCreateOptions<TKms>;
}): Promise<BearerDid>;
/**
* Given the W3C DID Document of a `did:ion` DID, return the verification method that will be used
* for signing messages and credentials. If given, the `methodId` parameter is used to select the
* verification method. If not given, the first verification method in the authentication property
* in the DID Document is used.
*
* @param params - The parameters for the `getSigningMethod` operation.
* @param params.didDocument - DID Document to get the verification method from.
* @param params.methodId - ID of the verification method to use for signing.
* @returns Verification method to use for signing.
*/
static getSigningMethod({ didDocument, methodId }: {
didDocument: DidDocument;
methodId?: string;
}): Promise<DidVerificationMethod>;
/**
* Instantiates a {@link BearerDid} object for the DID ION method from a given {@link PortableDid}.
*
* This method allows for the creation of a `BearerDid` object using a previously created DID's
* key material, DID document, and metadata.
*
* @example
* ```ts
* // Export an existing BearerDid to PortableDid format.
* const portableDid = await did.export();
* // Reconstruct a BearerDid object from the PortableDid.
* const did = await DidIon.import({ portableDid });
* ```
*
* @param params - The parameters for the import operation.
* @param params.portableDid - The PortableDid object to import.
* @param params.keyManager - Optionally specify an external Key Management System (KMS) used to
* generate keys and sign data. If not given, a new
* {@link LocalKeyManager} instance will be created and
* used.
* @returns A Promise resolving to a `BearerDid` object representing the DID formed from the
* provided PortableDid.
* @throws An error if the DID document does not contain any verification methods or the keys for
* any verification method are missing in the key manager.
*/
static import({ portableDid, keyManager }: {
keyManager?: CryptoApi & KeyImporterExporter<KmsImportKeyParams, KeyIdentifier, KmsExportKeyParams>;
portableDid: PortableDid;
}): Promise<BearerDid>;
/**
* Publishes a DID to a Sidetree node, making it publicly discoverable and resolvable.
*
* This method handles the publication of a DID Document associated with a `did:ion` DID to a
* Sidetree node.
*
* @remarks
* - This method is typically invoked automatically during the creation of a new DID unless the
* `publish` option is set to `false`.
* - For existing, unpublished DIDs, it can be used to publish the DID Document to a Sidetree node.
* - The method relies on the specified Sidetree node to interface with the network.
*
* @param params - The parameters for the `publish` operation.
* @param params.did - The `BearerDid` object representing the DID to be published.
* @param params.gatewayUri - Optional. The URI of a server involved in executing DID
* method operations. In the context of publishing, the
* endpoint is expected to be a Sidetree node. If not
* specified, a default node is used.
* @returns A Promise resolving to a boolean indicating whether the publication was successful.
*
* @example
* ```ts
* // Generate a new DID and keys but explicitly disable publishing.
* const did = await DidIon.create({ options: { publish: false } });
* // Publish the DID to the Sidetree network.
* const isPublished = await DidIon.publish({ did });
* // `isPublished` is true if the DID was successfully published.
* ```
*/
static publish({ did, gatewayUri }: {
did: BearerDid;
gatewayUri?: string;
}): Promise<DidRegistrationResult>;
/**
* Resolves a `did:ion` identifier to its corresponding DID document.
*
* This method performs the resolution of a `did:ion` DID, retrieving its DID Document from the
* Sidetree-based DID overlay network. The process involves querying a Sidetree node to retrieve
* the DID Document that corresponds to the given DID identifier.
*
* @remarks
* - If a `gatewayUri` option is not specified, a default node is used to access the Sidetree
* network.
* - It decodes the DID identifier and retrieves the associated DID Document and metadata.
* - In case of resolution failure, appropriate error information is returned.
*
* @example
* ```ts
* const resolutionResult = await DidIon.resolve('did:ion:example');
* ```
*
* @param didUri - The DID to be resolved.
* @param options - Optional parameters for resolving the DID. Unused by this DID method.
* @returns A Promise resolving to a {@link DidResolutionResult} object representing the result of the resolution.
*/
static resolve(didUri: string, options?: DidResolutionOptions): Promise<DidResolutionResult>;
}
/**
* The `DidIonUtils` class provides utility functions to support operations in the DID ION method.
*/
export declare class DidIonUtils {
/**
* Appends a specified path to a base URL, ensuring proper formatting of the resulting URL.
*
* This method is useful for constructing URLs for accessing various endpoints, such as Sidetree
* nodes in the ION network. It handles the nuances of URL path concatenation, including the
* addition or removal of leading/trailing slashes, to create a well-formed URL.
*
* @param params - The parameters for URL construction.
* @param params.baseUrl - The base URL to which the path will be appended.
* @param params.path - The path to append to the base URL.
* @returns The fully constructed URL string with the path appended to the base URL.
*/
static appendPathToUrl({ baseUrl, path }: {
baseUrl: string;
path: string;
}): string;
/**
* Computes the Long Form DID URI given an ION DID's recovery key, update key, services, and
* verification methods.
*
* @param params - The parameters for computing the Long Form DID URI.
* @param params.recoveryKey - The ION Recovery Key.
* @param params.updateKey - The ION Update Key.
* @param params.services - An array of services associated with the DID.
* @param params.verificationMethods - An array of verification methods associated with the DID.
* @returns A Promise resolving to the Long Form DID URI.
*/
static computeLongFormDidUri({ recoveryKey, updateKey, services, verificationMethods }: {
recoveryKey: Jwk;
updateKey: Jwk;
services: DidService[];
verificationMethods: DidIonVerificationMethod[];
}): Promise<string>;
/**
* Constructs a Sidetree Create Operation request for a DID document within the ION network.
*
* This method prepares the necessary payload for submitting a Create Operation to a Sidetree
* node, encapsulating the details of the DID document, recovery key, and update key.
*
* @param params - Parameters required to construct the Create Operation request.
* @param params.ionDocument - The DID document model containing public keys and service endpoints.
* @param params.recoveryKey - The recovery public key in JWK format.
* @param params.updateKey - The update public key in JWK format.
* @returns A promise resolving to the ION Create Operation request model, ready for submission to a Sidetree node.
*/
static constructCreateRequest({ ionDocument, recoveryKey, updateKey }: {
ionDocument: IonDocumentModel;
recoveryKey: Jwk;
updateKey: Jwk;
}): Promise<DidIonCreateRequest>;
/**
* Assembles an ION document model from provided services and verification methods
*
* This model serves as the foundation for a DID document in the ION network, facilitating the
* creation and management of decentralized identities. It translates service endpoints and
* public keys into a format compatible with the Sidetree protocol, ensuring the resulting DID
* document adheres to the required specifications for ION DIDs. This method is essential for
* constructing the payload needed to register or update DIDs within the ION network.
*
* @param params - The parameters containing the services and verification methods to include in the ION document.
* @param params.services - A list of service endpoints to be included in the DID document, specifying ways to interact with the DID subject.
* @param params.verificationMethods - A list of verification methods to be included, detailing the cryptographic keys and their intended uses within the DID document.
* @returns A Promise resolving to an `IonDocumentModel`, ready for use in Sidetree operations like DID creation and updates.
*/
static createIonDocument({ services, verificationMethods }: {
services: DidService[];
verificationMethods: DidIonVerificationMethod[];
}): Promise<IonDocumentModel>;
/**
* Normalize the given JWK to include only specific members and in lexicographic order.
*
* @param jwk - The JWK to normalize.
* @returns The normalized JWK.
*/
private static normalizeJwk;
}
//# sourceMappingURL=did-ion.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"did-ion.d.ts","sourceRoot":"","sources":["../../../src/methods/did-ion.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,aAAa,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAC/H,OAAO,KAAK,EAEV,gBAAgB,EAGjB,MAAM,iCAAiC,CAAC;AAKzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,2BAA2B,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACrH,OAAO,KAAK,EACV,UAAU,EACV,WAAW,EACX,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,2BAA2B,EAC5B,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAKrD;;GAEG;AACH,MAAM,WAAW,mBAAmB,CAAC,IAAI,CAAE,SAAQ,gBAAgB,CAAC,IAAI,CAAC;IACvE;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,QAAQ,CAAC,EAAE,UAAU,EAAE,CAAC;IAExB;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,mBAAmB,CAAC,EAAE,2BAA2B,CAAC,IAAI,CAAC,EAAE,CAAC;CAC3D;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,yFAAyF;IACzF,IAAI,EAAE,QAAQ,CAAC;IAEf,4EAA4E;IAC5E,UAAU,EAAE;QACV,0FAA0F;QAC1F,SAAS,EAAE,MAAM,CAAC;QAClB,mFAAmF;QACnF,kBAAkB,EAAE,MAAM,CAAC;KAC5B,CAAC;IAEF,+EAA+E;IAC/E,KAAK,EAAE;QACL,kFAAkF;QAClF,gBAAgB,EAAE,MAAM,CAAC;QACzB,2FAA2F;QAC3F,OAAO,EAAE;YACP;6BACiB;YACjB,MAAM,EAAE,MAAM,CAAC;YACf,oEAAoE;YACpE,QAAQ,EAAE,gBAAgB,CAAC;SAC5B,EAAE,CAAC;KACL,CAAA;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,WAAW,wBAAwB;IACvC;;;;;;;;;;;;OAYG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ;;;;;;;;;;;;;;;;;OAiBG;IACH,YAAY,EAAE,GAAG,CAAC;IAElB;;;;;;;;;;;;;;;;;OAiBG;IACH,QAAQ,EAAE,CAAC,2BAA2B,GAAG,MAAM,OAAO,2BAA2B,CAAC,EAAE,CAAC;CACtF;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAe,SAAQ,WAAW;IACjD,yDAAyD;IACzD,WAAW,EAAE,GAAG,CAAC;IAEjB,wDAAwD;IACxD,SAAS,EAAE,GAAG,CAAC;CAChB;AAED;;;;;;GAMG;AACH,oBAAY,uBAAuB;IACjC;;;OAGG;IACH,OAAO,YAAY;IAEnB;;;OAGG;IACH,SAAS,cAAc;IAEvB;;;OAGG;IACH,SAAS,cAAc;IAEvB;;OAEG;IACH,MAAM,WAAW;CAClB;AAqBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,qBAAa,MAAO,SAAQ,SAAS;IAEnC;;OAEG;IACH,OAAc,UAAU,SAAS;IAEjC;;;;;;;;;;;;;;;;;;;;;OAqBG;WACiB,MAAM,CAAC,IAAI,SAAS,SAAS,GAAG,SAAS,GAAG,SAAS,EAAE,EACzE,UAAkC,EAClC,OAAY,EACb,GAAE;QACD,UAAU,CAAC,EAAE,IAAI,CAAC;QAClB,OAAO,CAAC,EAAE,mBAAmB,CAAC,IAAI,CAAC,CAAC;KAChC,GAAG,OAAO,CAAC,SAAS,CAAC;IAwF3B;;;;;;;;;;OAUG;WACiB,gBAAgB,CAAC,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE;QAC9D,WAAW,EAAE,WAAW,CAAC;QACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAmBlC;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;WACiB,MAAM,CAAC,EAAE,WAAW,EAAE,UAAkC,EAAE,EAAE;QAC9E,UAAU,CAAC,EAAE,SAAS,GAAG,mBAAmB,CAAC,kBAAkB,EAAE,aAAa,EAAE,kBAAkB,CAAC,CAAC;QACpG,WAAW,EAAE,WAAW,CAAC;KAC1B,GAAG,OAAO,CAAC,SAAS,CAAC;IAYtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;WACiB,OAAO,CAAC,EAAE,GAAG,EAAE,UAAgC,EAAE,EAAE;QACrE,GAAG,EAAE,SAAS,CAAC;QACf,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAgElC;;;;;;;;;;;;;;;;;;;;;OAqBG;WACiB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,mBAAmB,CAAC;CA+D9G;AAED;;GAEG;AACH,qBAAa,WAAW;IACtB;;;;;;;;;;;OAWG;WACW,eAAe,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QAC/C,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;KACd,GAAG,MAAM;IAQV;;;;;;;;;;OAUG;WACiB,qBAAqB,CAAC,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,mBAAmB,EAAE,EAAE;QACnG,WAAW,EAAE,GAAG,CAAC;QACjB,SAAS,EAAE,GAAG,CAAC;QACf,QAAQ,EAAE,UAAU,EAAE,CAAC;QACvB,mBAAmB,EAAE,wBAAwB,EAAE,CAAC;KACjD,GAAG,OAAO,CAAC,MAAM,CAAC;IAkBnB;;;;;;;;;;;OAWG;WACiB,sBAAsB,CAAC,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,EAAE;QAClF,WAAW,EAAE,gBAAgB,CAAC;QAC9B,WAAW,EAAE,GAAG,CAAC;QACjB,SAAS,EAAE,GAAG,CAAA;KACf,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAWhC;;;;;;;;;;;;;OAaG;WACiB,iBAAiB,CAAC,EAAE,QAAQ,EAAE,mBAAmB,EAAE,EAAE;QACvE,QAAQ,EAAE,UAAU,EAAE,CAAC;QACvB,mBAAmB,EAAE,wBAAwB,EAAE,CAAA;KAChD,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAyC7B;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,YAAY;CAkB5B"}
+236
View File
@@ -0,0 +1,236 @@
import type { CryptoApi, KeyIdentifier, KmsExportKeyParams, KmsImportKeyParams, KeyImporterExporter, InferKeyGeneratorAlgorithm } from '@web5/crypto';
import { LocalKeyManager } from '@web5/crypto';
import type { PortableDid } from '../types/portable-did.js';
import type { DidCreateOptions, DidCreateVerificationMethod } from './did-method.js';
import type { DidDocument, DidResolutionOptions, DidResolutionResult, DidVerificationMethod } from '../types/did-core.js';
import { DidMethod } from './did-method.js';
import { BearerDid } from '../bearer-did.js';
/**
* Defines the set of options available when creating a new Decentralized Identifier (DID) with the
* 'did:jwk' method.
*
* Either the `algorithm` or `verificationMethods` option can be specified, but not both.
* - A new key will be generated using the algorithm identifier specified in either the `algorithm`
* property or the `verificationMethods` object's `algorithm` property.
* - If `verificationMethods` is given, it must contain exactly one entry since DID JWK only
* supports a single verification method.
* - If neither is given, the default is to generate a new Ed25519 key.
*
* @example
* ```ts
* // DID Creation
*
* // By default, when no options are given, a new Ed25519 key will be generated.
* const did = await DidJwk.create();
*
* // The algorithm to use for key generation can be specified as a top-level option.
* const did = await DidJwk.create({
* options: { algorithm = 'ES256K' }
* });
*
* // Or, alternatively as a property of the verification method.
* const did = await DidJwk.create({
* options: {
* verificationMethods: [{ algorithm = 'ES256K' }]
* }
* });
*
* // DID Creation with a KMS
* const keyManager = new LocalKeyManager();
* const did = await DidJwk.create({ keyManager });
*
* // DID Resolution
* const resolutionResult = await DidJwk.resolve({ did: did.uri });
*
* // Signature Operations
* const signer = await did.getSigner();
* const signature = await signer.sign({ data: new TextEncoder().encode('Message') });
* const isValid = await signer.verify({ data: new TextEncoder().encode('Message'), signature });
*
* // Import / Export
*
* // Export a BearerDid object to the PortableDid format.
* const portableDid = await did.export();
*
* // Reconstruct a BearerDid object from a PortableDid
* const did = await DidJwk.import(portableDid);
* ```
*/
export interface DidJwkCreateOptions<TKms> extends DidCreateOptions<TKms> {
/**
* Optionally specify the algorithm to be used for key generation.
*/
algorithm?: TKms extends CryptoApi ? InferKeyGeneratorAlgorithm<TKms> : InferKeyGeneratorAlgorithm<LocalKeyManager>;
/**
* Alternatively, specify the algorithm to be used for key generation of the single verification
* method in the DID Document.
*/
verificationMethods?: DidCreateVerificationMethod<TKms>[];
}
/**
* The `DidJwk` class provides an implementation of the `did:jwk` DID method.
*
* Features:
* - DID Creation: Create new `did:jwk` DIDs.
* - DID Key Management: Instantiate a DID object from an existing verification method key set or
* or a key in a Key Management System (KMS). If supported by the KMS, a DID's
* key can be exported to a portable DID format.
* - DID Resolution: Resolve a `did:jwk` to its corresponding DID Document.
* - Signature Operations: Sign and verify messages using keys associated with a DID.
*
* @remarks
* The `did:jwk` DID method uses a single JSON Web Key (JWK) to generate a DID and does not rely
* on any external system such as a blockchain or centralized database. This characteristic makes
* it suitable for use cases where a assertions about a DID Subject can be self-verifiable by
* third parties.
*
* The DID URI is formed by Base64URL-encoding the JWK and prefixing with `did:jwk:`. The DID
* Document of a `did:jwk` DID contains a single verification method, which is the JWK used
* to generate the DID. The verification method is identified by the key ID `#0`.
*
* @see {@link https://github.com/quartzjer/did-jwk/blob/main/spec.md | DID JWK Specification}
*
* @example
* ```ts
* // DID Creation
* const did = await DidJwk.create();
*
* // DID Creation with a KMS
* const keyManager = new LocalKeyManager();
* const did = await DidJwk.create({ keyManager });
*
* // DID Resolution
* const resolutionResult = await DidJwk.resolve({ did: did.uri });
*
* // Signature Operations
* const signer = await did.getSigner();
* const signature = await signer.sign({ data: new TextEncoder().encode('Message') });
* const isValid = await signer.verify({ data: new TextEncoder().encode('Message'), signature });
*
* // Key Management
*
* // Instantiate a DID object from an existing key in a KMS
* const did = await DidJwk.fromKeyManager({
* didUri: 'did:jwk:eyJrIjoiT0tQIiwidCI6IkV1c2UyNTYifQ',
* keyManager
* });
*
* // Instantiate a DID object from an existing verification method key
* const did = await DidJwk.fromKeys({
* verificationMethods: [{
* publicKeyJwk: {
* kty: 'OKP',
* crv: 'Ed25519',
* x: 'cHs7YMLQ3gCWjkacMURBsnEJBcEsvlsE5DfnsfTNDP4'
* },
* privateKeyJwk: {
* kty: 'OKP',
* crv: 'Ed25519',
* x: 'cHs7YMLQ3gCWjkacMURBsnEJBcEsvlsE5DfnsfTNDP4',
* d: 'bdcGE4KzEaekOwoa-ee3gAm1a991WvNj_Eq3WKyqTnE'
* }
* }]
* });
*
* // Convert a DID object to a portable format
* const portableDid = await DidJwk.toKeys({ did });
*
* // Reconstruct a DID object from a portable format
* const did = await DidJwk.fromKeys(portableDid);
* ```
*/
export declare class DidJwk extends DidMethod {
/**
* Name of the DID method, as defined in the DID JWK specification.
*/
static methodName: string;
/**
* Creates a new DID using the `did:jwk` method formed from a newly generated key.
*
* @remarks
* The DID URI is formed by Base64URL-encoding the JWK and prefixing with `did:jwk:`.
*
* Notes:
* - If no `options` are given, by default a new Ed25519 key will be generated.
* - The `algorithm` and `verificationMethods` options are mutually exclusive. If both are given,
* an error will be thrown.
*
* @example
* ```ts
* // DID Creation
* const did = await DidJwk.create();
*
* // DID Creation with a KMS
* const keyManager = new LocalKeyManager();
* const did = await DidJwk.create({ keyManager });
* ```
*
* @param params - The parameters for the create operation.
* @param params.keyManager - Optionally specify a Key Management System (KMS) used to generate
* keys and sign data.
* @param params.options - Optional parameters that can be specified when creating a new DID.
* @returns A Promise resolving to a {@link BearerDid} object representing the new DID.
*/
static create<TKms extends CryptoApi | undefined = undefined>({ keyManager, options }?: {
keyManager?: TKms;
options?: DidJwkCreateOptions<TKms>;
}): Promise<BearerDid>;
/**
* Given the W3C DID Document of a `did:jwk` DID, return the verification method that will be used
* for signing messages and credentials. If given, the `methodId` parameter is used to select the
* verification method. If not given, the first verification method in the DID Document is used.
*
* Note that for DID JWK, only one verification method can exist so specifying `methodId` could be
* considered redundant or unnecessary. The option is provided for consistency with other DID
* method implementations.
*
* @param params - The parameters for the `getSigningMethod` operation.
* @param params.didDocument - DID Document to get the verification method from.
* @param params.methodId - ID of the verification method to use for signing.
* @returns Verification method to use for signing.
*/
static getSigningMethod({ didDocument }: {
didDocument: DidDocument;
methodId?: string;
}): Promise<DidVerificationMethod>;
/**
* Instantiates a {@link BearerDid} object for the DID JWK method from a given {@link PortableDid}.
*
* This method allows for the creation of a `BearerDid` object using a previously created DID's
* key material, DID document, and metadata.
*
* @remarks
* The `verificationMethod` array of the DID document must contain exactly one key since the
* `did:jwk` method only supports a single verification method.
*
* @example
* ```ts
* // Export an existing BearerDid to PortableDid format.
* const portableDid = await did.export();
* // Reconstruct a BearerDid object from the PortableDid.
* const did = await DidJwk.import({ portableDid });
* ```
*
* @param params - The parameters for the import operation.
* @param params.portableDid - The PortableDid object to import.
* @param params.keyManager - Optionally specify an external Key Management System (KMS) used to
* generate keys and sign data. If not given, a new
* {@link LocalKeyManager} instance will be created and
* used.
* @returns A Promise resolving to a `BearerDid` object representing the DID formed from the provided keys.
* @throws An error if the DID document does not contain exactly one verification method.
*/
static import({ portableDid, keyManager }: {
keyManager?: CryptoApi & KeyImporterExporter<KmsImportKeyParams, KeyIdentifier, KmsExportKeyParams>;
portableDid: PortableDid;
}): Promise<BearerDid>;
/**
* Resolves a `did:jwk` identifier to a DID Document.
*
* @param didUri - The DID to be resolved.
* @param _options - Optional parameters for resolving the DID. Unused by this DID method.
* @returns A Promise resolving to a {@link DidResolutionResult} object representing the result of the resolution.
*/
static resolve(didUri: string, _options?: DidResolutionOptions): Promise<DidResolutionResult>;
}
//# sourceMappingURL=did-jwk.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"did-jwk.d.ts","sourceRoot":"","sources":["../../../src/methods/did-jwk.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,SAAS,EACT,aAAa,EACb,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,EACnB,0BAA0B,EAC3B,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,gBAAgB,EAAE,2BAA2B,EAAE,MAAM,iBAAiB,CAAC;AACrF,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAG1H,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAI7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,MAAM,WAAW,mBAAmB,CAAC,IAAI,CAAE,SAAQ,gBAAgB,CAAC,IAAI,CAAC;IACvE;;OAEG;IACH,SAAS,CAAC,EAAE,IAAI,SAAS,SAAS,GAC9B,0BAA0B,CAAC,IAAI,CAAC,GAChC,0BAA0B,CAAC,eAAe,CAAC,CAAC;IAEhD;;;OAGG;IACH,mBAAmB,CAAC,EAAE,2BAA2B,CAAC,IAAI,CAAC,EAAE,CAAC;CAC3D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuEG;AACH,qBAAa,MAAO,SAAQ,SAAS;IAEnC;;OAEG;IACH,OAAc,UAAU,SAAS;IAEjC;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;WACiB,MAAM,CAAC,IAAI,SAAS,SAAS,GAAG,SAAS,GAAG,SAAS,EAAE,EACzE,UAAkC,EAClC,OAAY,EACb,GAAE;QACD,UAAU,CAAC,EAAE,IAAI,CAAC;QAClB,OAAO,CAAC,EAAE,mBAAmB,CAAC,IAAI,CAAC,CAAC;KAChC,GAAG,OAAO,CAAC,SAAS,CAAC;IA4C3B;;;;;;;;;;;;;OAaG;WACiB,gBAAgB,CAAC,EAAE,WAAW,EAAE,EAAE;QACpD,WAAW,EAAE,WAAW,CAAC;QACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAiBlC;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;WACiB,MAAM,CAAC,EAAE,WAAW,EAAE,UAAkC,EAAE,EAAE;QAC9E,UAAU,CAAC,EAAE,SAAS,GAAG,mBAAmB,CAAC,kBAAkB,EAAE,aAAa,EAAE,kBAAkB,CAAC,CAAC;QACpG,WAAW,EAAE,WAAW,CAAC;KAC1B,GAAG,OAAO,CAAC,SAAS,CAAC;IAoBtB;;;;;;OAMG;WACiB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,mBAAmB,CAAC;CAyE3G"}
+499
View File
@@ -0,0 +1,499 @@
import type { MulticodecCode, MulticodecDefinition } from '@web5/common';
import type { Jwk, CryptoApi, KeyCompressor, KeyIdentifier, KmsExportKeyParams, KmsImportKeyParams, KeyImporterExporter, AsymmetricKeyConverter, InferKeyGeneratorAlgorithm } from '@web5/crypto';
import { LocalKeyManager } from '@web5/crypto';
import type { PortableDid } from '../types/portable-did.js';
import type { DidCreateOptions, DidCreateVerificationMethod } from './did-method.js';
import type { DidDocument, DidResolutionOptions, DidResolutionResult, DidVerificationMethod } from '../types/did-core.js';
import { DidMethod } from './did-method.js';
import { BearerDid } from '../bearer-did.js';
/**
* Defines the set of options available when creating a new Decentralized Identifier (DID) with the
* 'did:key' method.
*
* Either the `algorithm` or `verificationMethods` option can be specified, but not both.
* - A new key will be generated using the algorithm identifier specified in either the `algorithm`
* property or the `verificationMethods` object's `algorithm` property.
* - If `verificationMethods` is given, it must contain exactly one entry since DID Key only
* supports a single verification method.
* - If neither is given, the default is to generate a new Ed25519 key.
*
* @example
* ```ts
* // By default, when no options are given, a new Ed25519 key will be generated.
* const did = await DidKey.create();
*
* // The algorithm to use for key generation can be specified as a top-level option.
* const did = await DidKey.create({
* options: { algorithm = 'secp256k1' }
* });
*
* // Or, alternatively as a property of the verification method.
* const did = await DidKey.create({
* options: {
* verificationMethods: [{ algorithm = 'secp256k1' }]
* }
* });
*
* // DID Creation with a KMS
* const keyManager = new LocalKeyManager();
* const did = await DidKey.create({ keyManager });
*
* // DID Resolution
* const resolutionResult = await DidKey.resolve({ did: did.uri });
*
* // Signature Operations
* const signer = await did.getSigner();
* const signature = await signer.sign({ data: new TextEncoder().encode('Message') });
* const isValid = await signer.verify({ data: new TextEncoder().encode('Message'), signature });
*
* // Import / Export
*
* // Export a BearerDid object to the PortableDid format.
* const portableDid = await did.export();
*
* // Reconstruct a BearerDid object from a PortableDid
* const did = await DidKey.import(portableDid);
* ```
*/
export interface DidKeyCreateOptions<TKms> extends DidCreateOptions<TKms> {
/**
* Optionally specify the algorithm to be used for key generation.
*/
algorithm?: TKms extends CryptoApi ? InferKeyGeneratorAlgorithm<TKms> : InferKeyGeneratorAlgorithm<LocalKeyManager>;
/**
* Optionally specify an array of JSON-LD context links for the @context property of the DID
* document.
*
* The @context property provides a JSON-LD processor with the information necessary to interpret
* the DID document JSON. The default context URL is 'https://www.w3.org/ns/did/v1'.
*/
defaultContext?: string;
/**
* Optionally enable encryption key derivation during DID creation.
*
* By default, this option is set to `false`, which means encryption key derivation is not
* performed unless explicitly enabled.
*
* When set to `true`, an `X25519` key will be derived from the `Ed25519` public key used to
* create the DID. This feature enables the same DID to be used for encrypted communication, in
* addition to signature verification.
*
* Notes:
* - This option is ONLY applicable when the `algorithm` of the DID's public key is `Ed25519`.
* - Enabling this introduces specific cryptographic considerations that should be understood
* before using the same key pair for digital signatures and encrypted communication. See the following for more information:
*/
enableEncryptionKeyDerivation?: boolean;
/**
* Optionally enable experimental public key types during DID creation.
* By default, this option is set to `false`, which means experimental public key types are not
* supported.
*
* Note: This implementation of the DID Key method does not support any experimental public key
* types.
*/
enableExperimentalPublicKeyTypes?: boolean;
/**
* Optionally specify the format of the public key to be used for DID creation.
*/
publicKeyFormat?: keyof typeof DidKeyVerificationMethodType;
/**
* Alternatively, specify the algorithm to be used for key generation of the single verification
* method in the DID Document.
*/
verificationMethods?: DidCreateVerificationMethod<TKms>[];
}
/**
* Enumerates the types of keys that can be used in a DID Key document.
*
* The DID Key method supports various cryptographic key types. These key types are essential for
* the creation and management of DIDs and their associated cryptographic operations like signing
* and encryption.
*/
export declare enum DidKeyRegisteredKeyType {
/**
* Ed25519: A public-key signature system using the EdDSA (Edwards-curve Digital Signature
* Algorithm) and Curve25519.
*/
Ed25519 = "Ed25519",
/**
* secp256k1: A cryptographic curve used for digital signatures in a range of decentralized
* systems.
*/
secp256k1 = "secp256k1",
/**
* secp256r1: Also known as P-256 or prime256v1, this curve is used for cryptographic operations
* and is widely supported in various cryptographic libraries and standards.
*/
secp256r1 = "secp256r1",
/**
* X25519: A Diffie-Hellman key exchange algorithm using Curve25519.
*/
X25519 = "X25519"
}
/**
* Enumerates the verification method types supported by the DID Key method.
*
* This enum defines the URIs associated with common verification methods used in DID Documents.
* These URIs represent cryptographic suites or key types standardized for use across decentralized
* identifiers (DIDs).
*/
export declare const DidKeyVerificationMethodType: {
/** Represents an Ed25519 public key used for digital signatures. */
readonly Ed25519VerificationKey2020: "https://w3id.org/security/suites/ed25519-2020/v1";
/** Represents a JSON Web Key (JWK) used for digital signatures and key agreement protocols. */
readonly JsonWebKey2020: "https://w3id.org/security/suites/jws-2020/v1";
/** Represents an X25519 public key used for key agreement protocols. */
readonly X25519KeyAgreementKey2020: "https://w3id.org/security/suites/x25519-2020/v1";
};
/**
* The `DidKey` class provides an implementation of the 'did:key' DID method.
*
* Features:
* - DID Creation: Create new `did:key` DIDs.
* - DID Key Management: Instantiate a DID object from an existing verification method key set or
* or a key in a Key Management System (KMS). If supported by the KMS, a DID's
* key can be exported to a portable DID format.
* - DID Resolution: Resolve a `did:key` to its corresponding DID Document.
* - Signature Operations: Sign and verify messages using keys associated with a DID.
*
* @remarks
* The `did:key` DID method uses a single public key to generate a DID and does not rely
* on any external system such as a blockchain or centralized database. This characteristic makes
* it suitable for use cases where a assertions about a DID Subject can be self-verifiable by
* third parties.
*
* The method-specific identifier is formed by
* {@link https://datatracker.ietf.org/doc/html/draft-multiformats-multibase#name-base-58-bitcoin-encoding | Multibase base58-btc}
* encoding the concatenation of the
* {@link https://github.com/multiformats/multicodec/blob/master/README.md | Multicodec} identifier
* for the public key type and the raw public key bytes. To form the DID URI, the method-specific
* identifier is prefixed with the string 'did:key:'.
*
* This method can optionally derive an encryption key from the public key used to create the DID
* if and only if the public key algorithm is `Ed25519`. This feature enables the same DID to be
* used for encrypted communication, in addition to signature verification. To enable this
* feature when calling {@link DidKey.create | `DidKey.create()`}, first specify an `algorithm` of
* `Ed25519` or provide a `keySet` referencing an `Ed25519` key and then set the
* `enableEncryptionKeyDerivation` option to `true`.
*
* Note:
* - The authors of the DID Key specification have indicated that use of this method for long-lived
* use cases is only recommended when accompanied with high confidence that private keys are
* securely protected by software or hardware isolation.
*
* @see {@link https://w3c-ccg.github.io/did-method-key/ | DID Key Specification}
*
* @example
* ```ts
* // DID Creation
* const did = await DidKey.create();
*
* // DID Creation with a KMS
* const keyManager = new LocalKeyManager();
* const did = await DidKey.create({ keyManager });
*
* // DID Resolution
* const resolutionResult = await DidKey.resolve({ did: did.uri });
*
* // Signature Operations
* const signer = await did.getSigner();
* const signature = await signer.sign({ data: new TextEncoder().encode('Message') });
* const isValid = await signer.verify({ data: new TextEncoder().encode('Message'), signature });
*
* // Key Management
*
* // Instantiate a DID object from an existing key in a KMS
* const did = await DidKey.fromKeyManager({
* didUri: 'did:key:z6MkpUzNmYVTGpqhStxK8yRKXWCRNm1bGYz8geAg2zmjYHKX',
* keyManager
* });
*
* // Instantiate a DID object from an existing verification method key
* const did = await DidKey.fromKeys({
* verificationMethods: [{
* publicKeyJwk: {
* kty: 'OKP',
* crv: 'Ed25519',
* x: 'cHs7YMLQ3gCWjkacMURBsnEJBcEsvlsE5DfnsfTNDP4'
* },
* privateKeyJwk: {
* kty: 'OKP',
* crv: 'Ed25519',
* x: 'cHs7YMLQ3gCWjkacMURBsnEJBcEsvlsE5DfnsfTNDP4',
* d: 'bdcGE4KzEaekOwoa-ee3gAm1a991WvNj_Eq3WKyqTnE'
* }
* }]
* });
*
* // Convert a DID object to a portable format
* const portableDid = await DidKey.toKeys({ did });
*
* // Reconstruct a DID object from a portable format
* const did = await DidKey.fromKeys(portableDid);
* ```
*/
export declare class DidKey extends DidMethod {
/**
* Name of the DID method, as defined in the DID Key specification.
*/
static methodName: string;
/**
* Creates a new DID using the `did:key` method formed from a newly generated key.
*
* @remarks
* The DID URI is formed by
* {@link https://datatracker.ietf.org/doc/html/draft-multiformats-multibase#name-base-58-bitcoin-encoding | Multibase base58-btc}
* encoding the
* {@link https://github.com/multiformats/multicodec/blob/master/README.md | Multicodec}-encoded
* public key and prefixing with `did:key:`.
*
* This method can optionally derive an encryption key from the public key used to create the DID
* if and only if the public key algorithm is `Ed25519`. This feature enables the same DID to be
* used for encrypted communication, in addition to signature verification. To enable this
* feature, specify an `algorithm` of `Ed25519` as either a top-level option or in a
* `verificationMethod` and set the `enableEncryptionKeyDerivation` option to `true`.
*
* Notes:
* - If no `options` are given, by default a new Ed25519 key will be generated.
* - The `algorithm` and `verificationMethods` options are mutually exclusive. If both are given,
* an error will be thrown.
*
* @example
* ```ts
* // DID Creation
* const did = await DidKey.create();
*
* // DID Creation with a KMS
* const keyManager = new LocalKeyManager();
* const did = await DidKey.create({ keyManager });
* ```
*
* @param params - The parameters for the create operation.
* @param params.keyManager - Key Management System (KMS) used to generate keys and sign data.
* @param params.options - Optional parameters that can be specified when creating a new DID.
* @returns A Promise resolving to a {@link BearerDid} object representing the new DID.
*/
static create<TKms extends CryptoApi | undefined = undefined>({ keyManager, options }?: {
keyManager?: TKms;
options?: DidKeyCreateOptions<TKms>;
}): Promise<BearerDid>;
/**
* Given the W3C DID Document of a `did:key` DID, return the verification method that will be used
* for signing messages and credentials. With DID Key, the first verification method in the
* authentication property in the DID Document is used.
*
* Note that for DID Key, only one verification method intended for signing can exist so
* specifying `methodId` could be considered redundant or unnecessary. The option is provided for
* consistency with other DID method implementations.
*
* @param params - The parameters for the `getSigningMethod` operation.
* @param params.didDocument - DID Document to get the verification method from.
* @param params.methodId - ID of the verification method to use for signing.
* @returns Verification method to use for signing.
*/
static getSigningMethod({ didDocument }: {
didDocument: DidDocument;
methodId?: string;
}): Promise<DidVerificationMethod>;
/**
* Instantiates a {@link BearerDid} object for the DID Key method from a given {@link PortableDid}.
*
* This method allows for the creation of a `BearerDid` object using a previously created DID's
* key material, DID document, and metadata.
*
* @remarks
* The `verificationMethod` array of the DID document must contain exactly one key since the
* `did:key` method only supports a single verification method.
*
* @example
* ```ts
* // Export an existing BearerDid to PortableDid format.
* const portableDid = await did.export();
* // Reconstruct a BearerDid object from the PortableDid.
* const did = await DidKey.import({ portableDid });
* ```
*
* @param params - The parameters for the import operation.
* @param params.portableDid - The PortableDid object to import.
* @param params.keyManager - Optionally specify an external Key Management System (KMS) used to
* generate keys and sign data. If not given, a new
* {@link LocalKeyManager} instance will be created and
* used.
* @returns A Promise resolving to a `BearerDid` object representing the DID formed from the provided keys.
* @throws An error if the DID document does not contain exactly one verification method.
*/
static import({ portableDid, keyManager }: {
keyManager?: CryptoApi & KeyImporterExporter<KmsImportKeyParams, KeyIdentifier, KmsExportKeyParams>;
portableDid: PortableDid;
}): Promise<BearerDid>;
/**
* Resolves a `did:key` identifier to a DID Document.
*
* @param didUri - The DID to be resolved.
* @param options - Optional parameters for resolving the DID.
* @returns A Promise resolving to a {@link DidResolutionResult} object representing the result of the resolution.
*/
static resolve(didUri: string, options?: DidResolutionOptions): Promise<DidResolutionResult>;
/**
* Expands a did:key identifier to a DID Document.
*
* Reference: https://w3c-ccg.github.io/did-method-key/#document-creation-algorithm
*
* @param options
* @returns - A DID dodcument.
*/
private static createDocument;
/**
* Decoding a multibase-encoded multicodec value into a verification method
* that is suitable for verifying that encrypted information will be
* received by the intended recipient.
*/
private static createEncryptionMethod;
/**
* Decodes a multibase-encoded multicodec value into a verification method
* that is suitable for verifying digital signatures.
* @param options - Signature method creation algorithm inputs.
* @returns - A verification method.
*/
private static createSignatureMethod;
/**
* Transform a multibase-encoded multicodec value to public encryption key
* components that are suitable for encrypting messages to a receiver. A
* mathematical proof elaborating on the safety of performing this operation
* is available in:
* {@link https://eprint.iacr.org/2021/509.pdf | On using the same key pair for Ed25519 and an X25519 based KEM}
*/
private static deriveEncryptionKey;
/**
* Validates the structure and components of a DID URI against the `did:key` method specification.
*
* @param parsedDid - An object representing the parsed components of a DID URI, including the
* scheme, method, and method-specific identifier.
* @returns `true` if the DID URI meets the `did:key` method's structural requirements, `false` otherwise.
*
*/
private static validateIdentifier;
}
/**
* The `DidKeyUtils` class provides utility functions to support operations in the DID Key method.
*/
export declare class DidKeyUtils {
/**
* A mapping from JSON Web Key (JWK) property descriptors to multicodec names.
*
* This mapping is used to convert keys in JWK (JSON Web Key) format to multicodec format.
*
* @remarks
* The keys of this object are strings that describe the JOSE key type and usage,
* such as 'Ed25519:public', 'Ed25519:private', etc. The values are the corresponding multicodec
* names used to represent these key types.
*
* @example
* ```ts
* const multicodecName = JWK_TO_MULTICODEC['Ed25519:public'];
* // Returns 'ed25519-pub', the multicodec name for an Ed25519 public key
* ```
*/
private static JWK_TO_MULTICODEC;
/**
* Defines the expected byte lengths for public keys associated with different cryptographic
* algorithms, indexed by their multicodec code values.
*/
static MULTICODEC_PUBLIC_KEY_LENGTH: Record<number, number>;
/**
* A mapping from multicodec names to their corresponding JOSE (JSON Object Signing and Encryption)
* representations. This mapping facilitates the conversion of multicodec key formats to
* JWK (JSON Web Key) formats.
*
* @remarks
* The keys of this object are multicodec names, such as 'ed25519-pub', 'ed25519-priv', etc.
* The values are objects representing the corresponding JWK properties for that key type.
*
* @example
* ```ts
* const joseKey = MULTICODEC_TO_JWK['ed25519-pub'];
* // Returns a partial JWK for an Ed25519 public key
* ```
*/
private static MULTICODEC_TO_JWK;
/**
* Converts a JWK (JSON Web Key) to a Multicodec code and name.
*
* @example
* ```ts
* const jwk: Jwk = { crv: 'Ed25519', kty: 'OKP', x: '...' };
* const { code, name } = await DidKeyUtils.jwkToMulticodec({ jwk });
* ```
*
* @param params - The parameters for the conversion.
* @param params.jwk - The JSON Web Key to be converted.
* @returns A promise that resolves to a Multicodec definition.
*/
static jwkToMulticodec({ jwk }: {
jwk: Jwk;
}): Promise<MulticodecDefinition<MulticodecCode>>;
/**
* Returns the appropriate public key compressor for the specified cryptographic curve.
*
* @param curve - The cryptographic curve to use for the key conversion.
* @returns A public key compressor for the specified curve.
*/
static keyCompressor(curve: string): KeyCompressor['compressPublicKey'];
/**
* Returns the appropriate key converter for the specified cryptographic curve.
*
* @param curve - The cryptographic curve to use for the key conversion.
* @returns An `AsymmetricKeyConverter` for the specified curve.
*/
static keyConverter(curve: string): AsymmetricKeyConverter;
/**
* Converts a Multicodec code or name to parial JWK (JSON Web Key).
*
* @example
* ```ts
* const partialJwk = await DidKeyUtils.multicodecToJwk({ name: 'ed25519-pub' });
* ```
*
* @param params - The parameters for the conversion.
* @param params.code - Optional Multicodec code to convert.
* @param params.name - Optional Multicodec name to convert.
* @returns A promise that resolves to a JOSE format key.
*/
static multicodecToJwk({ code, name }: {
code?: MulticodecCode;
name?: string;
}): Promise<Jwk>;
/**
* Converts a public key in JWK (JSON Web Key) format to a multibase identifier.
*
* @remarks
* Note: All secp public keys are converted to compressed point encoding
* before the multibase identifier is computed.
*
* Per {@link https://github.com/multiformats/multicodec/blob/master/table.csv | Multicodec table}:
* Public keys for Elliptic Curve cryptography algorithms (e.g., secp256k1,
* secp256k1r1, secp384r1, etc.) are always represented with compressed point
* encoding (e.g., secp256k1-pub, p256-pub, p384-pub, etc.).
*
* Per {@link https://datatracker.ietf.org/doc/html/rfc8812#name-jose-and-cose-secp256k1-cur | RFC 8812}:
* "As a compressed point encoding representation is not defined for JWK
* elliptic curve points, the uncompressed point encoding defined there
* MUST be used. The x and y values represented MUST both be exactly
* 256 bits, with any leading zeros preserved."
*
* @example
* ```ts
* const publicKey = { crv: 'Ed25519', kty: 'OKP', x: '...' };
* const multibaseId = await DidKeyUtils.publicKeyToMultibaseId({ publicKey });
* ```
*
* @param params - The parameters for the conversion.
* @param params.publicKey - The public key in JWK format.
* @returns A promise that resolves to the multibase identifier.
*/
static publicKeyToMultibaseId({ publicKey }: {
publicKey: Jwk;
}): Promise<string>;
}
//# sourceMappingURL=did-key.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"did-key.d.ts","sourceRoot":"","sources":["../../../src/methods/did-key.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,238 @@
import type { CryptoApi, LocalKeyManager, InferKeyGeneratorAlgorithm } from '@web5/crypto';
import type { BearerDid } from '../bearer-did.js';
import type { DidMetadata } from '../types/portable-did.js';
import type { DidDocument, DidResolutionResult, DidResolutionOptions, DidVerificationMethod } from '../types/did-core.js';
import { DidVerificationRelationship } from '../types/did-core.js';
/**
* Represents options during the creation of a Decentralized Identifier (DID).
*
* Implementations of this interface may contain properties and methods that provide specific
* options or metadata during the DID creation processes following specific DID method
* specifications.
*/
export interface DidCreateOptions<TKms> {
/**
* Optional. An array of verification methods to be included in the DID document.
*/
verificationMethods?: DidCreateVerificationMethod<TKms>[];
}
/**
* Options for additional verification methods added to the DID Document during the creation of a
* new Decentralized Identifier (DID).
*/
export interface DidCreateVerificationMethod<TKms> extends Pick<Partial<DidVerificationMethod>, 'controller' | 'id' | 'type'> {
/**
* The name of the cryptographic algorithm to be used for key generation.
*
* Examples might include `Ed25519` and `ES256K` but will vary depending on the DID method
* specification and the key management system in use.
*
* @example
* ```ts
* const verificationMethod: DidCreateVerificationMethod = {
* algorithm: 'Ed25519'
* };
* ```
*/
algorithm: TKms extends CryptoApi ? InferKeyGeneratorAlgorithm<TKms> : InferKeyGeneratorAlgorithm<LocalKeyManager>;
/**
* Optionally specify the purposes for which a verification method is intended to be used in a DID
* document.
*
* The `purposes` property defines the specific
* {@link DidVerificationRelationship | verification relationships} between the DID subject and
* the verification method. This enables the verification method to be utilized for distinct
* actions such as authentication, assertion, key agreement, capability delegation, and others. It
* is important for verifiers to recognize that a verification method must be associated with the
* relevant purpose in the DID document to be valid for that specific use case.
*
* @example
* ```ts
* const verificationMethod: DidCreateVerificationMethod = {
* algorithm: 'Ed25519',
* controller: 'did:example:1234',
* purposes: ['authentication', 'assertionMethod']
* };
* ```
*/
purposes?: (DidVerificationRelationship | keyof typeof DidVerificationRelationship)[];
}
/**
* Defines the API for a specific DID method. It includes functionalities for creating and resolving
* DIDs.
*
* @typeparam T - The type of the DID instance associated with this method.
* @typeparam O - The type of the options used for creating the DID.
*/
export interface DidMethodApi<TKms extends CryptoApi | undefined = CryptoApi, TDid extends BearerDid = BearerDid, TOptions extends DidCreateOptions<TKms> = DidCreateOptions<TKms>> extends DidMethodResolver {
/**
* The name of the DID method.
*
* For example, in the DID `did:example:123456`, "example" would be the method name.
*/
methodName: string;
new (): DidMethod;
/**
* Creates a new DID.
*
* This function should generate a new DID in accordance with the DID method specification being
* implemented, using the provided `keyManager`, and optionally, any provided `options`.
*
* @param params - The parameters used to create the DID.
* @param params.keyManager - Optional. The cryptographic API used for key management.
* @param params.options - Optional. The options used for creating the DID.
* @returns A promise that resolves to the newly created DID instance.
*/
create(params: {
keyManager?: TKms;
options?: TOptions;
}): Promise<TDid>;
/**
* Given a DID Document, return the verification method that will be used for signing messages and
* credentials.
*
* If given, the `methodId` parameter is used to select the verification method. If not given, a
* DID method specific approach is taken to selecting the verification method to return.
*
* @param params - The parameters for the `getSigningMethod` operation.
* @param params.didDocument - DID Document to get the verification method from.
* @param params.methodId - ID of the verification method to use for signing.
* @returns A promise that resolves to the erification method to use for signing.
*/
getSigningMethod(params: {
didDocument: DidDocument;
methodId?: string;
}): Promise<DidVerificationMethod>;
}
/**
* Defines the interface for resolving a DID using a specific DID method.
*
* A DID resolver takes a DID URI as input and returns a {@link DidResolutionResult} object.
*
* @property {string} methodName - The name of the DID method.
* @method resolve - Asynchronous method to resolve a DID URI. Takes the DID URI and optional resolution options.
*/
export interface DidMethodResolver {
/**
* The name of the DID method.
*
* For example, in the DID `did:example:123456`, "example" would be the method name.
*/
methodName: string;
new (): DidMethod;
/**
* Resolves a DID URI.
*
* This function should resolve the DID URI in accordance with the DID method specification being
* implemented, using the provided `options`.
*
* @param didUri - The DID URI to be resolved.
* @param options - Optional. The options used for resolving the DID.
* @returns A {@link DidResolutionResult} object containing the DID document and metadata or an error.
*/
resolve(didUri: string, options?: DidResolutionOptions): Promise<DidResolutionResult>;
}
/**
* Represents the result of a Decentralized Identifier (DID) registration operation.
*
* This type encapsulates the complete outcome of registering a DID, including the registration
* metadata, the DID document (if registration is successful), and metadata about the DID document.
*/
export interface DidRegistrationResult {
/**
* The DID document resulting from the registration process, if successful.
*
* If the registration operation was successful, this MUST contain a DID document
* corresponding to the DID. If the registration is unsuccessful, this value MUST be empty.
*
* @see {@link https://www.w3.org/TR/did-core/#dfn-diddocument | DID Core Specification, § DID Document}
*/
didDocument: DidDocument | null;
/**
* Metadata about the DID Document.
*
* This structure contains information about the DID Document like creation and update timestamps,
* deactivation status, versioning information, and other details relevant to the DID Document.
*
* @see {@link https://www.w3.org/TR/did-core/#dfn-diddocumentmetadata | DID Core Specification, § DID Document Metadata}
*/
didDocumentMetadata: DidMetadata;
/**
* A metadata structure consisting of values relating to the results of the DID registration
* process.
*
* This structure is REQUIRED, and in the case of an error in the registration process,
* this MUST NOT be empty. If the registration is not successful, this structure MUST contain an
* `error` property describing the error.
*/
didRegistrationMetadata: DidRegistrationMetadata;
}
/**
* Represents metadata related to the result of a DID registration operation.
*
* This type includes fields that provide information about the outcome of a DID registration
* process (e.g., create, update, deactivate), including any errors that occurred.
*
* This metadata typically changes between invocations of the `create`, `update`, and `deactivate`
* functions, as it represents data about the registration process itself.
*/
export type DidRegistrationMetadata = {
/**
* An error code indicating issues encountered during the DID registration process.
*
* While the DID Core specification does not define a specific set of error codes for the result
* returned by the `create`, `update`, or `deactivate` functions, it is recommended to use the
* error codes defined in the DID Specification Registries for
* {@link https://www.w3.org/TR/did-spec-registries/#error | DID Resolution Metadata }.
*
* Recommended error codes include:
* - `internalError`: An unexpected error occurred during DID registration process.
* - `invalidDid`: The provided DID is invalid.
* - `invalidDidDocument`: The provided DID document does not conform to valid syntax.
* - `invalidDidDocumentLength`: The byte length of the provided DID document does not match the expected value.
* - `invalidSignature`: Verification of a signature failed.
* - `methodNotSupported`: The DID method specified is not supported.
* - Custom error codes can also be provided as strings.
*/
error?: string;
[key: string]: any;
};
/**
* Base abstraction for all Decentralized Identifier (DID) method implementations.
*
* This base class serves as a foundational structure upon which specific DID methods
* can be implemented. Subclasses should furnish particular method and data models adherent
* to various DID methods, taking care to adhere to the
* {@link https://www.w3.org/TR/did-core/ | W3C DID Core specification} and the
* respective DID method specifications.
*/
export declare class DidMethod {
/**
* MUST be implemented by all DID method implementations that extend {@link DidMethod}.
*
* Given the W3C DID Document of a DID, return the verification method that will be used for
* signing messages and credentials. If given, the `methodId` parameter is used to select the
* verification method. If not given, each DID method implementation will select a default
* verification method from the DID Document.
*
* @param _params - The parameters for the `getSigningMethod` operation.
* @param _params.didDocument - DID Document to get the verification method from.
* @param _params.methodId - ID of the verification method to use for signing.
* @returns Verification method to use for signing.
*/
static getSigningMethod(_params: {
didDocument: DidDocument;
methodId?: string;
}): Promise<DidVerificationMethod | undefined>;
/**
* MUST be implemented by all DID method implementations that extend {@link DidMethod}.
*
* Resolves a DID URI to a DID Document.
*
* @param _didUri - The DID to be resolved.
* @param _options - Optional parameters for resolving the DID.
* @returns A Promise resolving to a {@link DidResolutionResult} object representing the result of the resolution.
*/
static resolve(_didUri: string, _options?: DidResolutionOptions): Promise<DidResolutionResult>;
}
//# sourceMappingURL=did-method.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"did-method.d.ts","sourceRoot":"","sources":["../../../src/methods/did-method.ts"],"names":[],"mappings":"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"}
+37
View File
@@ -0,0 +1,37 @@
import type { DidResolutionOptions, DidResolutionResult } from '../types/did-core.js';
import { DidMethod } from './did-method.js';
/**
* The `DidWeb` class provides an implementation of the `did:web` DID method.
*
* Features:
* - DID Resolution: Resolve a `did:web` to its corresponding DID Document.
*
* @remarks
* The `did:web` method uses a web domain's existing reputation and aims to integrate decentralized
* identities with the existing web infrastructure to drive adoption. It leverages familiar web
* security models and domain ownership to provide accessible, interoperable digital identity
* management.
*
* @see {@link https://w3c-ccg.github.io/did-method-web/ | DID Web Specification}
*
* @example
* ```ts
* // DID Resolution
* const resolutionResult = await DidWeb.resolve({ did: did.uri });
* ```
*/
export declare class DidWeb extends DidMethod {
/**
* Name of the DID method, as defined in the DID Web specification.
*/
static methodName: string;
/**
* Resolves a `did:web` identifier to a DID Document.
*
* @param didUri - The DID to be resolved.
* @param _options - Optional parameters for resolving the DID. Unused by this DID method.
* @returns A Promise resolving to a {@link DidResolutionResult} object representing the result of the resolution.
*/
static resolve(didUri: string, _options?: DidResolutionOptions): Promise<DidResolutionResult>;
}
//# sourceMappingURL=did-web.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"did-web.d.ts","sourceRoot":"","sources":["../../../src/methods/did-web.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAGnG,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,MAAO,SAAQ,SAAS;IAEnC;;OAEG;IACH,OAAc,UAAU,SAAS;IAEjC;;;;;;OAMG;WACiB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,mBAAmB,CAAC;CAuD3G"}
@@ -0,0 +1,87 @@
/// <reference types="node" resolution-mode="require"/>
import type { AbstractLevel } from 'abstract-level';
import type { DidResolutionResult } from '../types/did-core.js';
import type { DidResolverCache } from '../types/did-resolution.js';
/**
* Configuration parameters for creating a LevelDB-based cache for DID resolution results.
*
* Allows customization of the underlying database instance, storage location, and cache
* time-to-live (TTL) settings.
*/
export type DidResolverCacheLevelParams = {
/**
* Optional. An instance of `AbstractLevel` to use as the database. If not provided, a new
* LevelDB instance will be created at the specified `location`.
*/
db?: AbstractLevel<string | Buffer | Uint8Array, string, string>;
/**
* Optional. The file system path or IndexedDB name where the LevelDB store will be created.
* Defaults to 'DATA/DID_RESOLVERCACHE' if not specified.
*/
location?: string;
/**
* Optional. The time-to-live for cache entries, expressed as a string (e.g., '1h', '15m').
* Determines how long a cache entry should remain valid before being considered expired. Defaults
* to '15m' if not specified.
*/
ttl?: string;
};
/**
* A Level-based cache implementation for storing and retrieving DID resolution results.
*
* This cache uses LevelDB for storage, allowing data persistence across process restarts or
* browser refreshes. It's suitable for both Node.js and browser environments.
*
* @remarks
* The LevelDB cache keeps data in memory for fast access and also writes to the filesystem in
* Node.js or indexedDB in browsers. Time-to-live (TTL) for cache entries is configurable.
*
* @example
* ```
* const cache = new DidResolverCacheLevel({ ttl: '15m' });
* ```
*/
export declare class DidResolverCacheLevel implements DidResolverCache {
/** The underlying LevelDB store used for caching. */
private cache;
/** The time-to-live for cache entries in milliseconds. */
private ttl;
constructor({ db, location, ttl }?: DidResolverCacheLevelParams);
/**
* Retrieves a DID resolution result from the cache.
*
* If the cached item has exceeded its TTL, it's scheduled for deletion and undefined is returned.
*
* @param did - The DID string used as the key for retrieving the cached result.
* @returns The cached DID resolution result or undefined if not found or expired.
*/
get(did: string): Promise<DidResolutionResult | void>;
/**
* Stores a DID resolution result in the cache with a TTL.
*
* @param did - The DID string used as the key for storing the result.
* @param value - The DID resolution result to be cached.
* @returns A promise that resolves when the operation is complete.
*/
set(did: string, value: DidResolutionResult): Promise<void>;
/**
* Deletes a DID resolution result from the cache.
*
* @param did - The DID string used as the key for deletion.
* @returns A promise that resolves when the operation is complete.
*/
delete(did: string): Promise<void>;
/**
* Clears all entries from the cache.
*
* @returns A promise that resolves when the operation is complete.
*/
clear(): Promise<void>;
/**
* Closes the underlying LevelDB store.
*
* @returns A promise that resolves when the store is closed.
*/
close(): Promise<void>;
}
//# sourceMappingURL=resolver-cache-level.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"resolver-cache-level.d.ts","sourceRoot":"","sources":["../../../src/resolver/resolver-cache-level.ts"],"names":[],"mappings":";AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAKpD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAChE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAEnE;;;;;GAKG;AACH,MAAM,MAAM,2BAA2B,GAAG;IACxC;;;OAGG;IACH,EAAE,CAAC,EAAE,aAAa,CAAC,MAAM,GAAG,MAAM,GAAG,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAEjE;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAA;AAyBD;;;;;;;;;;;;;;GAcG;AACH,qBAAa,qBAAsB,YAAW,gBAAgB;IAC5D,qDAAqD;IACrD,OAAO,CAAC,KAAK,CAAC;IAEd,0DAA0D;IAC1D,OAAO,CAAC,GAAG,CAAS;gBAER,EACV,EAAE,EACF,QAAmC,EACnC,GAAW,EACZ,GAAE,2BAAgC;IAKnC;;;;;;;OAOG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC;IAwB3D;;;;;;OAMG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAO3D;;;;;OAKG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlC;;;;OAIG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB;;;;OAIG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAGvB"}
@@ -0,0 +1,9 @@
import type { DidResolverCache } from '../types/did-resolution.js';
/**
* No-op cache that is used as the default cache for did-resolver.
*
* The motivation behind using a no-op cache as the default stems from the desire to maximize the
* potential for this library to be used in as many JS runtimes as possible.
*/
export declare const DidResolverCacheNoop: DidResolverCache;
//# sourceMappingURL=resolver-cache-noop.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"resolver-cache-noop.d.ts","sourceRoot":"","sources":["../../../src/resolver/resolver-cache-noop.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAEnE;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,EAAE,gBAgBlC,CAAC"}
@@ -0,0 +1,109 @@
import type { DidMethodResolver } from '../methods/did-method.js';
import type { DidResolver, DidResolverCache, DidUrlDereferencer } from '../types/did-resolution.js';
import type { DidDereferencingOptions, DidDereferencingResult, DidResolutionOptions, DidResolutionResult } from '../types/did-core.js';
/**
* Parameters for configuring the `UniversalResolver` class, which is responsible for resolving
* decentralized identifiers (DIDs) to their corresponding DID documents.
*
* This type specifies the essential components required by the `UniversalResolver` to perform
* DID resolution and dereferencing. It includes an array of `DidMethodResolver` instances,
* each capable of resolving DIDs for a specific method, and optionally, a cache for storing
* resolved DID documents to improve resolution efficiency.
*/
export type UniversalResolverParams = {
/**
* An array of `DidMethodResolver` instances.
*
* Each resolver in this array is designed to handle a specific DID method, enabling the
* `DidResolver` to support multiple DID methods simultaneously.
*/
didResolvers: DidMethodResolver[];
/**
* An optional `DidResolverCache` instance used for caching resolved DID documents.
*
* Providing a cache implementation can significantly enhance resolution performance by avoiding
* redundant resolutions for previously resolved DIDs. If omitted, a no-operation cache is used,
* which effectively disables caching.
*/
cache?: DidResolverCache;
};
/**
* The `DidResolver` class provides mechanisms for resolving Decentralized Identifiers (DIDs) to
* their corresponding DID documents.
*
* The class is designed to handle various DID methods by utilizing an array of `DidMethodResolver`
* instances, each responsible for a specific DID method.
*
* Providing a cache implementation can significantly enhance resolution performance by avoiding
* redundant resolutions for previously resolved DIDs. If omitted, a no-operation cache is used,
* which effectively disables caching.
*
* Usage:
* - Construct the `DidResolver` with an array of `DidMethodResolver` instances and an optional cache.
* - Use `resolve` to resolve a DID to its DID Resolution Result.
* - Use `dereference` to extract specific resources from a DID URL, like service endpoints or verification methods.
*
* @example
* ```ts
* const resolver = new DidResolver({
* didResolvers: [<array of DidMethodResolver instances>],
* cache: new DidResolverCacheNoop()
* });
*
* const resolutionResult = await resolver.resolve('did:example:123456');
* const dereferenceResult = await resolver.dereference({ didUri: 'did:example:123456#key-1' });
* ```
*/
export declare class UniversalResolver implements DidResolver, DidUrlDereferencer {
/**
* A cache for storing resolved DID documents.
*/
private cache;
/**
* A map to store method resolvers against method names.
*/
private didResolvers;
/**
* Constructs a new `DidResolver`.
*
* @param params - The parameters for constructing the `DidResolver`.
*/
constructor({ cache, didResolvers }: UniversalResolverParams);
/**
* Resolves a DID to a DID Resolution Result.
*
* If the DID Resolution Result is present in the cache, it returns the cached result. Otherwise,
* it uses the appropriate method resolver to resolve the DID, stores the resolution result in the
* cache, and returns the resolultion result.
*
* @param didUri - The DID or DID URL to resolve.
* @returns A promise that resolves to the DID Resolution Result.
*/
resolve(didUri: string, options?: DidResolutionOptions): Promise<DidResolutionResult>;
/**
* Dereferences a DID (Decentralized Identifier) URL to a corresponding DID resource.
*
* This method interprets the DID URL's components, which include the DID method, method-specific
* identifier, path, query, and fragment, and retrieves the related resource as per the DID Core
* specifications.
*
* The dereferencing process involves resolving the DID contained in the DID URL to a DID document,
* and then extracting the specific part of the document identified by the fragment in the DID URL.
* If no fragment is specified, the entire DID document is returned.
*
* This method supports resolution of different components within a DID document such as service
* endpoints and verification methods, based on their IDs. It accommodates both full and
* DID URLs as specified in the DID Core specification.
*
* More information on DID URL dereferencing can be found in the
* {@link https://www.w3.org/TR/did-core/#did-url-dereferencing | DID Core specification}.
*
* TODO: This is a partial implementation and does not fully implement DID URL dereferencing. (https://github.com/TBD54566975/web5-js/issues/387)
*
* @param didUrl - The DID URL string to dereference.
* @param [_options] - Input options to the dereference function. Optional.
* @returns a {@link DidDereferencingResult}
*/
dereference(didUrl: string, _options?: DidDereferencingOptions): Promise<DidDereferencingResult>;
}
//# sourceMappingURL=universal-resolver.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"universal-resolver.d.ts","sourceRoot":"","sources":["../../../src/resolver/universal-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACpG,OAAO,KAAK,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,mBAAmB,EAAe,MAAM,sBAAsB,CAAC;AAOpJ;;;;;;;;GAQG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC;;;;;OAKG;IACH,YAAY,EAAE,iBAAiB,EAAE,CAAC;IAElC;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,gBAAgB,CAAC;CAC1B,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,iBAAkB,YAAW,WAAW,EAAE,kBAAkB;IACvE;;OAEG;IACH,OAAO,CAAC,KAAK,CAAmB;IAEhC;;OAEG;IACH,OAAO,CAAC,YAAY,CAA6C;IAEjE;;;;OAIG;gBACS,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,uBAAuB;IAQ5D;;;;;;;;;OASG;IACU,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAuClG;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACG,WAAW,CACf,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,uBAAuB,GACjC,OAAO,CAAC,sBAAsB,CAAC;CAyEnC"}
+523
View File
@@ -0,0 +1,523 @@
import { Jwk } from '@web5/crypto';
/**
* Represents metadata related to the process of DID dereferencing.
*
* This type includes fields that provide information about the outcome of a DID dereferencing operation,
* including the content type of the returned resource and any errors that occurred during the dereferencing process.
*
* @see {@link https://www.w3.org/TR/did-core/#did-url-dereferencing-metadata | DID Core Specification, § DID URL Dereferencing Metadata}
*/
export type DidDereferencingMetadata = {
/**
* The Media Type of the returned contentStream SHOULD be expressed using this property if
* dereferencing is successful.
*/
contentType?: string;
/**
* The error code from the dereferencing process. This property is REQUIRED when there is an
* error in the dereferencing process. The value of this property MUST be a single keyword
* expressed as an ASCII string. The possible property values of this field SHOULD be registered
* in the {@link https://www.w3.org/TR/did-spec-registries/ | DID Specification Registries}.
* The DID Core specification defines the following common error values:
*
* - `invalidDidUrl`: The DID URL supplied to the DID URL dereferencing function does not conform
* to valid syntax.
* - `notFound`: The DID URL dereferencer was unable to find the `contentStream` resulting from
* this dereferencing request.
*
* @see {@link https://www.w3.org/TR/did-core/#did-url-dereferencing-metadata | DID Core Specification, § DID URL Dereferencing Metadata}
*/
error?: string;
[key: string]: any;
};
/**
* Represents the options that can be used during the process of DID dereferencing.
*
* This interface allows the caller to specify preferences and additional parameters for the DID
* dereferencing operation.
*
* @see {@link https://www.w3.org/TR/did-core/#did-url-dereferencing-options}
*/
export interface DidDereferencingOptions {
/** The Media Type that the caller prefers for contentStream. */
accept?: string;
/** Additional properties used during DID dereferencing. */
[key: string]: any;
}
/**
* Represents the result of a DID dereferencing operation.
*
* This type encapsulates the outcomes of the DID URL dereferencing process, including metadata
* about the dereferencing operation, the content stream retrieved (if any), and metadata about the
* content stream.
*
* @see {@link https://www.w3.org/TR/did-core/#did-url-dereferencing | DID Core Specification, § DID URL Dereferencing}
*/
export type DidDereferencingResult = {
/**
* A metadata structure consisting of values relating to the results of the DID URL dereferencing
* process. This structure is REQUIRED, and in the case of an error in the dereferencing process,
* this MUST NOT be empty. Properties defined by this specification are in 7.2.2 DID URL
* Dereferencing Metadata. If the dereferencing is not successful, this structure MUST contain an
* `error` property describing the error.
*/
dereferencingMetadata: DidDereferencingMetadata;
/**
* If the `dereferencing` function was called and successful, this MUST contain a resource
* corresponding to the DID URL. The contentStream MAY be a resource such as:
* - a DID document that is serializable in one of the conformant representations
* - a Verification Method
* - a service.
* - any other resource format that can be identified via a Media Type and obtained through the
* resolution process.
*
* If the dereferencing is unsuccessful, this value MUST be empty.
*/
contentStream: DidResource | null;
/**
* If the dereferencing is successful, this MUST be a metadata structure, but the structure MAY be
* empty. This structure contains metadata about the contentStream. If the contentStream is a DID
* document, this MUST be a didDocumentMetadata structure as described in DID Resolution. If the
* dereferencing is unsuccessful, this output MUST be an empty metadata structure.
*/
contentMetadata: DidDocumentMetadata;
};
/**
* A set of data describing the Decentralized Identifierr (DID) subject.
*
* A DID Document contains information associated with the DID, such as cryptographic public keys
* and service endpoints, enabling trustable interactions associated with the DID subject.
*
* - Cryptographic public keys - Used by the DID subject or a DID delegate to authenticate itself
* and prove its association with the DID.
* - Service endpoints - Used to communicate or interact with the DID subject or associated
* entities. Examples include discovery, agent, social networking, file
* storage, and verifiable credential repository services.
*
* A DID Document can be retrieved by resolving a DID, as described in
* {@link https://www.w3.org/TR/did-core/#did-resolution | DID Core Specification, § DID Resolution}.
*/
export interface DidDocument {
/**
* A JSON-LD context link, which provides a JSON-LD processor with the information necessary to
* interpret the DID document JSON. The default context URL is 'https://www.w3.org/ns/did/v1'.
*/
'@context'?: 'https://www.w3.org/ns/did/v1' | string | (string | Record<string, any>)[];
/**
* The DID Subject to which this DID Document pertains.
*
* The `id` property is REQUIRED and must be a valid DID.
*
* @see {@link https://www.w3.org/TR/did-core/#did-subject | DID Core Specification, § DID Subject}
*/
id: string;
/**
* A DID subject can have multiple identifiers for different purposes, or at different times.
* The assertion that two or more DIDs (or other types of URI) refer to the same DID subject can
* be made using the `alsoKnownAs` property.
*
* @see {@link https://www.w3.org/TR/did-core/#also-known-as | DID Core Specification, § Also Known As}
*/
alsoKnownAs?: string[];
/**
* A DID controller is an entity that is authorized to make changes to a DID document. Typically,
* only the DID Subject (i.e., the value of `id` property in the DID document) is authoritative.
* However, another DID can be specified as the DID controller, and when doing so, any
* verification methods contained in the DID document for the other DID should be accepted as
* authoritative. In other words, proofs created by the controller DID should be considered
* equivalent to proofs created by the DID Subject.
*
* @see {@link https://www.w3.org/TR/did-core/#did-controller | DID Core Specification, § DID Controller}
*/
controller?: string | string[];
/**
* A DID document can express verification methods, such as cryptographic public keys, which can
* be used to authenticate or authorize interactions with the DID subject or associated parties.
*
* @see {@link https://www.w3.org/TR/did-core/#verification-methods | DID Core Specification, § Verification Methods}
*/
verificationMethod?: DidVerificationMethod[];
/**
* The `assertionMethod` verification relationship is used to specify how the DID subject is
* expected to express claims, such as for the purposes of issuing a Verifiable Credential.
*
* @see {@link https://www.w3.org/TR/did-core/#assertion | DID Core Specification, § Assertion}
*/
assertionMethod?: (DidVerificationMethod | string)[];
/**
* The `authentication` verification relationship is used to specify how the DID subject is expected
* to be authenticated, for purposes such as logging into a website or engaging in any sort of
* challenge-response protocol.
* @see {@link https://www.w3.org/TR/did-core/#authentication | DID Core Specification, § Authentication}
*/
authentication?: (DidVerificationMethod | string)[];
/**
* The `keyAgreement` verification relationship is used to specify how an entity can generate
* encryption material in order to transmit confidential information intended for the DID
* subject, such as for the purposes of establishing a secure communication channel with the
* recipient.
*
* @see {@link https://www.w3.org/TR/did-core/#key-agreement | DID Core Specification, § Key Agreement}
*/
keyAgreement?: (DidVerificationMethod | string)[];
/**
* The `capabilityDelegation` verification relationship is used to specify a mechanism that might
* be used by the DID subject to delegate a cryptographic capability to another party, such as
* delegating the authority to access a specific HTTP API to a subordinate.
*
* @see {@link https://www.w3.org/TR/did-core/#capability-delegation | DID Core Specification, § Capability Delegation}
*/
capabilityDelegation?: (DidVerificationMethod | string)[];
/**
* The `capabilityInvocation` verification relationship is used to specify a verification method
* that might be used by the DID subject to invoke a cryptographic capability, such as the
* authorization to update the DID Document.
*/
capabilityInvocation?: (DidVerificationMethod | string)[];
/**
* Services are used in DID documents to express ways of communicating with the DID subject or
* associated entities. A service can be any type of service the DID subject wants to advertise,
* including decentralized identity management services for further discovery, authentication,
* authorization, or interaction.
*
* @see {@link https://www.w3.org/TR/did-core/#services | DID Core Specification, § Services}
*/
service?: DidService[];
}
/**
* Represents metadata about the DID document resulting from a DID resolution operation.
*
* This metadata typically does not change between invocations of the `resolve` and
* `resolveRepresentation` functions unless the DID document changes, as it represents metadata
* about the DID document.
*
* @see {@link https://www.w3.org/TR/did-core/#did-document-metadata | DID Core Specification, § DID Document Metadata}
*/
export interface DidDocumentMetadata {
/**
* Timestamp of the Create operation.
*
* The value of the property MUST be a string formatted as an XML Datetime normalized to
* UTC 00:00:00 and without sub-second decimal precision. For example: `2020-12-20T19:17:47Z`.
*/
created?: string;
/**
* Timestamp of the last Update operation for the document version which was resolved.
*
* The value of the property MUST follow the same formatting rules as the `created` property.
* The `updated` property is omitted if an Update operation has never been performed on the DID
* document. If an `updated` property exists, it can be the same value as the `created` property
* when the difference between the two timestamps is less than one second.
*/
updated?: string;
/**
* Whether the DID has been deactivated.
*
* If a DID has been deactivated, DID document metadata MUST include this property with the
* boolean value `true`. If a DID has not been deactivated, this properrty is OPTIONAL, but if
* present, MUST have the boolean value `false`.
*/
deactivated?: boolean;
/**
* Version ID of the last Update operation for the document version which was resolved.
*/
versionId?: string;
/**
* Timestamp of the next Update operation if the resolved document version is not the latest
* version of the document.
*
* The value of the property MUST follow the same formatting rules as the `created` property.
*/
nextUpdate?: string;
/**
* Version ID of the next Update operation if the resolved document version is not the latest
* version of the document.
*/
nextVersionId?: string;
/**
* A DID method can define different forms of a DID that are logically equivalent. An example is
* when a DID takes one form prior to registration in a verifiable data registry and another form
* after such registration. In this case, the DID method specification might need to express one
* or more DIDs that are logically equivalent to the resolved DID as a property of the DID
* document. This is the purpose of the `equivalentId` property.
*
* A requesting party is expected to retain the values from the id and equivalentId properties to
* ensure any subsequent interactions with any of the values they contain are correctly handled as
* logically equivalent (e.g., retain all variants in a database so an interaction with any one
* maps to the same underlying account).
*
* @see {@link https://www.w3.org/TR/did-core/#dfn-equivalentid | DID Core Specification, § DID Document Metadata}
*/
equivalentId?: string[];
/**
* The `canonicalId` property is identical to the `equivalentId` property except:
* - it is associated with a single value rather than a set
* - the DID is defined to be the canonical ID for the DID subject within the scope of the
* containing DID document.
*
* A requesting party is expected to use the `canonicalId` value as its primary ID value for the
* DID subject and treat all other equivalent values as secondary aliases (e.g., update
* corresponding primary references in their systems to reflect the new canonical ID directive).
*
* @see {@link https://www.w3.org/TR/did-core/#dfn-canonicalid | DID Core Specification, § DID Document Metadata}
*/
canonicalId?: string;
[key: string]: any;
}
/**
* Represents metadata related to the result of a DID resolution operation.
*
* This type includes fields that provide information about the outcome of a DID resolution process,
* including the content type of the returned DID document and any errors that occurred during the
* resolution process.
*
* This metadata typically changes between invocations of the `resolve` and `resolveRepresentation`
* functions, as it represents data about the resolution process itself.
*
* @see {@link https://www.w3.org/TR/did-core/#did-resolution-metadata | DID Core Specification, § DID Resolution Metadata}
*/
export type DidResolutionMetadata = {
/**
* The Media Type of the returned `didDocumentStream`.
*
* This property is REQUIRED if resolution is successful and if the `resolveRepresentation`
* function was called. This property MUST NOT be present if the `resolve` function was called.
* The value of this property MUST be an ASCII string that is the Media Type of the conformant
* representations. The caller of the `resolveRepresentation` function MUST use this value when
* determining how to parse and process the `didDocumentStream` returned by this function into the
* data model.
*/
contentType?: string;
/**
* An error code indicating issues encountered during the DID Resolution or DID URL
* Dereferencing process.
*
* Defined error codes include:
* - `internalError`: An unexpected error occurred during DID Resolution or DID URL
* dereferencing process.
* - `invalidDid`: The provided DID is invalid.
* - `methodNotSupported`: The DID method specified is not supported.
* - `notFound`: The DID or DID URL does not exist.
* - `representationNotSupported`: The DID document representation is not supported.
* - Custom error codes can also be provided as strings.
*
* @see {@link https://www.w3.org/TR/did-core/#did-resolution-metadata | DID Core Specification, § DID Resolution Metadata}
* @see {@link https://www.w3.org/TR/did-spec-registries/#error | DID Specification Registries, § Error}
*/
error?: string;
[key: string]: any;
};
/**
* DID Resolution input metadata.
*
* The DID Core specification defines the following common properties:
* - `accept`: The Media Type that the caller prefers for the returned representation of the DID
* Document.
*
* The possible properties within this structure and their possible values are registered in the
* {@link https://www.w3.org/TR/did-spec-registries/#did-resolution-options | DID Specification Registries}.
*
* @see {@link https://www.w3.org/TR/did-core/#did-resolution-options | DID Core Specification, § DID Resolution Options}
*/
export interface DidResolutionOptions {
/**
* The Media Type that the caller prefers for the returned representation of the DID Document.
*
* This property is REQUIRED if the `resolveRepresentation` function was called. This property
* MUST NOT be present if the `resolve` function was called.
*
* The value of this property MUST be an ASCII string that is the Media Type of the conformant
* representations. The caller of the `resolveRepresentation` function MUST use this value when
* determining how to parse and process the `didDocumentStream` returned by this function into the
* data model.
*
* @see {@link https://www.w3.org/TR/did-core/#did-resolution-options | DID Core Specification, § DID Resolution Options}
*/
accept?: string;
[key: string]: any;
}
/**
* Represents the result of a Decentralized Identifier (DID) resolution operation.
*
* This type encapsulates the complete outcome of resolving a DID, including the resolution metadata,
* the DID document (if resolution is successful), and metadata about the DID document.
*
* @see {@link https://www.w3.org/TR/did-core/#did-resolution | DID Core Specification, § DID Resolution}
*/
export type DidResolutionResult = {
/**
* A JSON-LD context link, which provides the JSON-LD processor with the information necessary to
* interpret the resolution result JSON. The default context URL is
* 'https://w3id.org/did-resolution/v1'.
*/
'@context'?: 'https://w3id.org/did-resolution/v1' | string | (string | Record<string, any>)[];
/**
* A metadata structure consisting of values relating to the results of the DID resolution
* process.
*
* This structure is REQUIRED, and in the case of an error in the resolution process,
* this MUST NOT be empty. If the resolution is not successful, this structure MUST contain an
* `error` property describing the error.
*
* @see {@link https://www.w3.org/TR/did-core/#dfn-didresolutionmetadata | DID Core Specification, § DID Resolution Metadata}
*/
didResolutionMetadata: DidResolutionMetadata;
/**
* The DID document resulting from the resolution process, if successful.
*
* If the `resolve` function was called and successful, this MUST contain a DID document
* corresponding to the DID. If the resolution is unsuccessful, this value MUST be empty.
*
* @see {@link https://www.w3.org/TR/did-core/#dfn-diddocument | DID Core Specification, § DID Document}
*/
didDocument: DidDocument | null;
/**
* Metadata about the DID Document.
*
* This structure contains information about the DID Document like creation and update timestamps,
* deactivation status, versioning information, and other details relevant to the DID Document.
*
* @see {@link https://www.w3.org/TR/did-core/#dfn-diddocumentmetadata | DID Core Specification, § DID Document Metadata}
*/
didDocumentMetadata: DidDocumentMetadata;
};
/**
* A DID Resource is either a DID Document, a DID Verification method or a DID Service
*/
export type DidResource = DidDocument | DidService | DidVerificationMethod;
/**
* Services are used in DID documents to express ways of communicating with the DID subject or
* associated entities. A service can be any type of service the DID subject wants to advertise.
*
* @see {@link https://www.w3.org/TR/did-core/#services}
*/
export type DidService = {
/**
* Identifier of the service.
*
* The `id` property is REQUIRED. It MUST be a URI conforming to
* {@link https://datatracker.ietf.org/doc/html/rfc3986 | RFC3986} and MUST be unique within the
* DID document.
*/
id: string;
/**
* The type of service being described.
*
* The `type` property is REQUIRED. It MUST be a string. To maximize interoperability, the value
* SHOULD be registered in the
* {@link https://www.w3.org/TR/did-spec-registries/ | DID Specification Registries}. Examples of
* service types can be found in
* {@link https://www.w3.org/TR/did-spec-registries/#service-types | § Service Types}.
*/
type: string;
/**
* A URI that can be used to interact with the DID service.
*
* The value of the `serviceEndpoint` property MUST be a string, an object containing key/value
* pairs, or an array composed of strings or objects. All string values MUST be valid URIs
* conforming to {@link https://datatracker.ietf.org/doc/html/rfc3986 | RFC3986}.
*/
serviceEndpoint: DidServiceEndpoint | DidServiceEndpoint[];
[key: string]: any;
};
/**
* A service endpoint is a URI (Uniform Resource Identifier) that can be used to interact with the
* DID service.
*
* The value of the `serviceEndpoint` property MUST be a string or an object containing key/value
* pairs. All string values MUST be valid URIs conforming to
* {@link https://datatracker.ietf.org/doc/html/rfc3986 | RFC3986}.
*
* @see {@link https://www.w3.org/TR/did-core/#dfn-serviceendpoint | RFC3986, § 5.4 Services}
*/
export type DidServiceEndpoint = string | Record<string, any>;
/**
* Represents a verification method in the context of a DID document.
*
* A verification method is a mechanism by which a DID controller can cryptographically assert proof
* of ownership or control over a DID or DID document. This can include, but is not limited to,
* cryptographic public keys or other data that can be used to authenticate or authorize actions.
*
* @see {@link https://www.w3.org/TR/did-core/#verification-methods | DID Core Specification, § Verification Methods}
*/
export interface DidVerificationMethod {
/**
* The identifier of the verification method, which must be a URI.
*/
id: string;
/**
* The type of the verification method.
*
* To maximize interoperability this value SHOULD be one of the valid verification method types
* registered in the {@link https://www.w3.org/TR/did-spec-registries/#verification-method-types | DID Specification Registries}.
*/
type: string;
/**
* The DID of the entity that controls this verification method.
*/
controller: string;
/**
* (Optional) A public key in JWK format.
*
* A JSON Web Key (JWK) that conforms to {@link https://datatracker.ietf.org/doc/html/rfc7517 | RFC 7517}.
*/
publicKeyJwk?: Jwk;
/**
* (Optional) A public key in Multibase format.
*
* A multibase key that conforms to the draft
* {@link https://datatracker.ietf.org/doc/draft-multiformats-multibase/ | Multibase specification}.
*/
publicKeyMultibase?: string;
}
/**
* Represents the various verification relationships defined in a DID document.
*
* These verification relationships indicate the intended usage of verification methods within a DID
* document. Each relationship signifies a different purpose or context in which a verification
* method can be used, such as authentication, assertionMethod, keyAgreement, capabilityDelegation,
* and capabilityInvocation. The array provides a standardized set of relationship names for
* consistent referencing and implementation across different DID methods.
*
* @see {@link https://www.w3.org/TR/did-core/#verification-relationships | DID Core Specification, § Verification Relationships}
*/
export declare enum DidVerificationRelationship {
/**
* Specifies how the DID subject is expected to be authenticated. This is commonly used for
* purposes like logging into a website or participating in challenge-response protocols.
*
* @see {@link https://www.w3.org/TR/did-core/#authentication | DID Core Specification, § Authentication}
*/
authentication = "authentication",
/**
* Specifies how the DID subject is expected to express claims, such as for issuing Verifiable
* Credentials. This relationship is typically used when the DID subject is the issuer of a
* credential.
*
* @see {@link https://www.w3.org/TR/did-core/#assertion | DID Core Specification, § Assertion}
*/
assertionMethod = "assertionMethod",
/**
* Specifies how an entity can generate encryption material to communicate confidentially with the
* DID subject. Often used in scenarios requiring secure communication channels.
*
* @see {@link https://www.w3.org/TR/did-core/#key-agreement | DID Core Specification, § Key Agreement}
*/
keyAgreement = "keyAgreement",
/**
* Specifies a verification method used by the DID subject to invoke a cryptographic capability.
* This is frequently associated with authorization actions, like updating the DID Document.
*
* @see {@link https://www.w3.org/TR/did-core/#capability-invocation | DID Core Specification, § Capability Invocation}
*/
capabilityInvocation = "capabilityInvocation",
/**
* Specifies a mechanism used by the DID subject to delegate a cryptographic capability to another
* party. This can include delegating access to a specific resource or API.
*
* @see {@link https://www.w3.org/TR/did-core/#capability-delegation | DID Core Specification, § Capability Delegation}
*/
capabilityDelegation = "capabilityDelegation"
}
//# sourceMappingURL=did-core.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"did-core.d.ts","sourceRoot":"","sources":["../../../src/types/did-core.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,85 @@
import type { KeyValueStore } from '@web5/common';
import type { DidDereferencingOptions, DidDereferencingResult, DidResolutionOptions, DidResolutionResult } from './did-core.js';
/**
* Represents the interface for resolving a Decentralized Identifier (DID) to its corresponding DID
* document.
*
* The `DidResolver` interface defines a single method, `resolve`, which takes a DID URL as input
* and returns a `Promise` that resolves to a `DidResolutionResult`. This result contains the DID
* document associated with the given DID, along with metadata about the resolution process.
*
* Implementations of this interface are expected to support resolution of DIDs according to the
* specific rules and methods defined by the DID scheme in use.
*
* More information on DID URL dereferencing can be found in the
* {@link https://www.w3.org/TR/did-core/#did-resolution | DID Core specification}.
*
* @example
* ```typescript
* const resolutionResult = await didResolver.resolve('did:example:123456789abcdefghi');
* ```
*/
export interface DidResolver {
/**
* Resolves a DID URI to a DID document and associated metadata.
*
* This function should resolve the DID URI in accordance with the relevant DID method
* specification, using the provided `options`.
*
* @param didUri - The DID URI to be resolved.
* @param options - Optional. The options used for resolving the DID.
* @returns A {@link DidResolutionResult} object containing the DID document and metadata or an
* error.
*/
resolve(didUrl: string, options?: DidResolutionOptions): Promise<DidResolutionResult>;
}
/**
* Interface for cache implementations used by to store resolved DID documents.
*/
export interface DidResolverCache extends KeyValueStore<string, DidResolutionResult | void> {
}
/**
* Represents the interface for dereferencing a DID URL to a specific resource within a DID
* document.
*
* The `DidUrlDereferencer` interface defines a single method, `dereference`, which takes a DID URL
* as input and returns a `Promise` that resolves to a `DidDereferencingResult`. This result
* includes the dereferenced resource (if found) and metadata about the dereferencing process.
*
* Dereferencing a DID URL involves parsing the URL to identify the specific part of the DID
* document being referenced, which could be a verification method, a service endpoint, or the
* entire document itself.
*
* Implementations of this interface must adhere to the dereferencing mechanisms defined in the DID
* Core specifications, handling various components of the DID URL including the DID itself, path,
* query, and fragment.
*
* More information on DID URL dereferencing can be found in the
* {@link https://www.w3.org/TR/did-core/#did-url-dereferencing | DID Core specification}.
*
* @example
* ```typescript
* const dereferenceResult = await didUrlDereferencer.dereference('did:example:123456789abcdefghi#keys-1');
* ```
*/
export interface DidUrlDereferencer {
/**
* Dereferences a DID (Decentralized Identifier) URL to a corresponding DID resource.
*
* This method interprets the DID URL's components, which include the DID method, method-specific
* identifier, path, query, and fragment, and retrieves the related resource as per the DID Core
* specifications.
*
* @param didUrl - The DID URL string to dereference.
* @param options - Input options to the dereference function. Optional.
* @returns a {@link DidDereferencingResult}
*/
dereference(didUrl: string, options?: DidDereferencingOptions): Promise<DidDereferencingResult>;
}
/**
* A constant representing an empty DID Resolution Result. This object is used as the basis for a
* result of DID resolution and is typically augmented with additional properties by the
* DID method resolver.
*/
export declare const EMPTY_DID_RESOLUTION_RESULT: DidResolutionResult;
//# sourceMappingURL=did-resolution.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"did-resolution.d.ts","sourceRoot":"","sources":["../../../src/types/did-resolution.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,KAAK,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEhI;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,WAAW;IAC1B;;;;;;;;;;OAUG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;CACvF;AAED;;GAEG;AACH,MAAM,WAAW,gBAAiB,SAAQ,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,IAAI,CAAC;CAAG;AAE9F;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;;;;;;;;OAUG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,uBAAuB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;CACjG;AAED;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,EAAE,mBAKzC,CAAC"}
+28
View File
@@ -0,0 +1,28 @@
/**
* Represents a cryptographic key with associated multicodec metadata.
*
* The `KeyWithMulticodec` type encapsulates a cryptographic key along with optional multicodec
* information. It is primarily used in functions that convert between cryptographic keys and their
* string representations, ensuring that the key's format and encoding are preserved and understood
* across different systems and applications.
*/
export type KeyWithMulticodec = {
/**
* A `Uint8Array` representing the raw bytes of the cryptographic key. This is the primary data of
* the type and is essential for cryptographic operations.
*/
keyBytes: Uint8Array;
/**
* An optional number representing the multicodec code. This code uniquely identifies the encoding
* format or protocol associated with the key. The presence of this code is crucial for decoding
* the key correctly in different contexts.
*/
multicodecCode?: number;
/**
* An optional string representing the human-readable name of the multicodec. This name provides
* an easier way to identify the encoding format or protocol of the key, especially when the
* numerical code is not immediately recognizable.
*/
multicodecName?: string;
};
//# sourceMappingURL=multibase.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"multibase.d.ts","sourceRoot":"","sources":["../../../src/types/multibase.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;OAGG;IACH,QAAQ,EAAE,UAAU,CAAC;IAErB;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB,CAAC"}
@@ -0,0 +1,59 @@
import type { Jwk } from '@web5/crypto';
import type { DidDocument, DidDocumentMetadata } from './did-core.js';
/**
* Represents metadata about a DID resulting from create, update, or deactivate operations.
*/
export interface DidMetadata extends DidDocumentMetadata {
/**
* For DID methods that support publishing, the `published` property indicates whether the DID
* document has been published to the respective network.
*
* A `true` value signifies that the DID document is publicly accessible on the network (e.g.,
* Mainline DHT), allowing it to be resolved by others. A `false` value implies the DID document
* is not published, limiting its visibility to public resolution. Absence of this property
* indicates that the DID method does not support publishing.
*/
published?: boolean;
}
/**
* Format to document a DID identifier, along with its associated data, which can be exported,
* saved to a file, or imported. The intent is bundle all of the necessary metadata to enable usage
* of the DID in different contexts.
*/
/**
* Format that documents the key material and metadata of a Decentralized Identifier (DID) to enable
* usage of the DID in different contexts.
*
* This format is useful for exporting, saving to a file, or importing a DID across process
* boundaries or between different DID method implementations.
*
* @example
* ```ts
* // Generate a new DID.
* const did = await DidExample.create();
*
* // Export to a PortableDid.
* const portableDid = await did.export();
*
* // Instantiate a BearerDid object from a PortableDid.
* const importedDid = await DidExample.import(portableDid);
* // The `importedDid` object should be equivalent to the original `did` object.
* ```
*/
export interface PortableDid {
/** {@inheritDoc Did#uri} */
uri: string;
/**
* The DID document associated with this DID.
*
* @see {@link https://www.w3.org/TR/did-core/#dfn-diddocument | DID Core Specification, § DID Document}
*/
document: DidDocument;
/** {@inheritDoc DidMetadata} */
metadata: DidMetadata;
/**
* An optional array of private keys associated with the DID document's verification methods.
*/
privateKeys?: Jwk[];
}
//# sourceMappingURL=portable-did.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"portable-did.d.ts","sourceRoot":"","sources":["../../../src/types/portable-did.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAExC,OAAO,KAAK,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEtE;;GAEG;AACH,MAAM,WAAW,WAAY,SAAQ,mBAAmB;IACtD;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;GAIG;AACH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,WAAW;IAC1B,4BAA4B;IAC5B,GAAG,EAAE,MAAM,CAAC;IAEZ;;;;OAIG;IACH,QAAQ,EAAE,WAAW,CAAC;IAEtB,gCAAgC;IAChC,QAAQ,EAAE,WAAW,CAAC;IAEtB;;OAEG;IACH,WAAW,CAAC,EAAE,GAAG,EAAE,CAAC;CACrB"}
+378
View File
@@ -0,0 +1,378 @@
import type { Jwk } from '@web5/crypto';
import type { RequireOnly } from '@web5/common';
import type { KeyWithMulticodec } from './types/multibase.js';
import { DidService, DidDocument, DidVerificationMethod, DidVerificationRelationship } from './types/did-core.js';
/**
* Represents a Decentralized Web Node (DWN) service in a DID Document.
*
* A DWN DID service is a specialized type of DID service with the `type` set to
* `DecentralizedWebNode`. It includes specific properties `enc` and `sig` that are used to identify
* the public keys that can be used to interact with the DID Subject. The values of these properties
* are strings or arrays of strings containing one or more verification method `id` values present in
* the same DID document. If the `enc` and/or `sig` properties are an array of strings, an entity
* interacting with the DID subject is expected to use the verification methods in the order they
* are listed.
*
* @example
* ```ts
* const service: DwnDidService = {
* id: 'did:example:123#dwn',
* type: 'DecentralizedWebNode',
* serviceEndpoint: 'https://dwn.tbddev.org/dwn0',
* enc: 'did:example:123#key-1',
* sig: 'did:example:123#key-2'
* }
* ```
*
* @see {@link https://identity.foundation/decentralized-web-node/spec/ | DIF Decentralized Web Node (DWN) Specification}
*/
export interface DwnDidService extends DidService {
/**
* One or more verification method `id` values that can be used to encrypt information
* intended for the DID subject.
*/
enc?: string | string[];
/**
* One or more verification method `id` values that will be used by the DID subject to sign data
* or by another entity to verify signatures created by the DID subject.
*/
sig: string | string[];
}
/**
* Extracts the fragment part of a Decentralized Identifier (DID) verification method identifier.
*
* This function takes any input and aims to return only the fragment of a DID identifier,
* which comes after the '#' symbol in a DID string. It's designed specifically for handling
* DID verification method identifiers. The function returns undefined for non-string inputs, inputs
* that do not contain a '#', or complex data structures like objects or arrays, ensuring that only
* the fragment part of a DID string is extracted when present.
*
* @example
* ```ts
* console.log(extractDidFragment("did:example:123#key-1")); // Output: "key-1"
* console.log(extractDidFragment("did:example:123")); // Output: undefined
* console.log(extractDidFragment({ id: "did:example:123#0", type: "JsonWebKey" })); // Output: undefined
* console.log(extractDidFragment(undefined)); // Output: undefined
* ```
*
* @param input - The input to be processed. Can be of any type, but the function is designed
* to work with strings that represent DID verification method identifiers.
* @returns The fragment part of the DID identifier if the input is a string containing a '#'.
* Returns an empty string for all other inputs, including non-string types, strings
* without a '#', and complex data structures.
*/
export declare function extractDidFragment(input: unknown): string | undefined;
/**
* Retrieves services from a given DID document, optionally filtered by `id` or `type`.
*
* If no `id` or `type` filters are provided, all defined services are returned.
*
* The given DID Document must adhere to the
* {@link https://www.w3.org/TR/did-core/ | W3C DID Core Specification}.
*
* @example
* ```ts
* const didDocument = { ... }; // W3C DID document
* const services = getServices({ didDocument, type: 'DecentralizedWebNode' });
* ```
*
* @param params - An object containing input parameters for retrieving services.
* @param params.didDocument - The DID document from which services are retrieved.
* @param params.id - Optional. A string representing the specific service ID to match. If provided, only the service with this ID will be returned.
* @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.
* @returns An array of services. If no matching service is found, an empty array is returned.
*/
export declare function getServices({ didDocument, id, type }: {
didDocument: DidDocument;
id?: string;
type?: string;
}): DidService[];
/**
* Retrieves a verification method object from a DID document if there is a match for the given
* public key.
*
* This function searches the verification methods in a given DID document for a match with the
* provided public key (either in JWK or multibase format). If a matching verification method is
* found it is returned. If no match is found `null` is returned.
*
*
* @example
* ```ts
* const didDocument = {
* // ... contents of a DID document ...
* };
* const publicKeyJwk = { kty: 'OKP', crv: 'Ed25519', x: '...' };
*
* const verificationMethod = await getVerificationMethodByKey({
* didDocument,
* publicKeyJwk
* });
* ```
*
* @param params - An object containing input parameters for retrieving the verification method ID.
* @param params.didDocument - The DID document to search for the verification method.
* @param params.publicKeyJwk - The public key in JSON Web Key (JWK) format to match against the verification methods in the DID document.
* @param params.publicKeyMultibase - The public key as a multibase encoded string to match against the verification methods in the DID document.
* @returns A promise that resolves with the matching verification method, or `null` if no match is found.
* @throws Throws an `Error` if the `didDocument` parameter is missing or if the `didDocument` does not contain any verification methods.
*/
export declare function getVerificationMethodByKey({ didDocument, publicKeyJwk, publicKeyMultibase }: {
didDocument: DidDocument;
publicKeyJwk?: Jwk;
publicKeyMultibase?: string;
}): Promise<DidVerificationMethod | null>;
/**
* Retrieves all verification methods from a given DID document, including embedded methods.
*
* This function consolidates all verification methods into a single array for easy access and
* processing. It checks both the primary `verificationMethod` array and the individual verification
* relationship properties `authentication`, `assertionMethod`, `keyAgreement`,
* `capabilityInvocation`, and `capabilityDelegation` for embedded methods.
*
* The given DID Document must adhere to the
* {@link https://www.w3.org/TR/did-core/ | W3C DID Core Specification}.
*
* @example
* ```ts
* const didDocument = { ... }; // W3C DID document
* const verificationMethods = getVerificationMethods({ didDocument });
* ```
*
* @param params - An object containing input parameters for retrieving verification methods.
* @param params.didDocument - The DID document from which verification methods are retrieved.
* @returns An array of `DidVerificationMethod`. If no verification methods are found, an empty array is returned.
* @throws Throws an `TypeError` if the `didDocument` parameter is missing.
*/
export declare function getVerificationMethods({ didDocument }: {
didDocument: DidDocument;
}): DidVerificationMethod[];
/**
* Retrieves all DID verification method types from a given DID document.
*
* The given DID Document must adhere to the
* {@link https://www.w3.org/TR/did-core/ | W3C DID Core Specification}.
*
* @example
* ```ts
* const didDocument = {
* verificationMethod: [
* {
* 'id' : 'did:example:123#key-0',
* 'type' : 'Ed25519VerificationKey2018',
* 'controller' : 'did:example:123',
* 'publicKeyBase58' : '3M5RCDjPTWPkKSN3sxUmmMqHbmRPegYP1tjcKyrDbt9J'
* },
* {
* 'id' : 'did:example:123#key-1',
* 'type' : 'X25519KeyAgreementKey2019',
* 'controller' : 'did:example:123',
* 'publicKeyBase58' : 'FbQWLPRhTH95MCkQUeFYdiSoQt8zMwetqfWoxqPgaq7x'
* },
* {
* 'id' : 'did:example:123#key-3',
* 'type' : 'JsonWebKey2020',
* 'controller' : 'did:example:123',
* 'publicKeyJwk' : {
* 'kty' : 'EC',
* 'crv' : 'P-256',
* 'x' : 'Er6KSSnAjI70ObRWhlaMgqyIOQYrDJTE94ej5hybQ2M',
* 'y' : 'pPVzCOTJwgikPjuUE6UebfZySqEJ0ZtsWFpj7YSPGEk'
* }
* }
* ]
* },
* const vmTypes = getVerificationMethodTypes({ didDocument });
* console.log(vmTypes);
* // Output: ['Ed25519VerificationKey2018', 'X25519KeyAgreementKey2019', 'JsonWebKey2020']
* ```
*
* @param params - An object containing input parameters for retrieving types.
* @param params.didDocument - The DID document from which types are retrieved.
* @returns An array of types. If no types were found, an empty array is returned.
*/
export declare function getVerificationMethodTypes({ didDocument }: {
didDocument: DidDocument;
}): string[];
/**
* Retrieves a list of DID verification relationships by a specific method ID from a DID document.
*
* This function examines the specified DID document to identify any verification relationships
* (e.g., `authentication`, `assertionMethod`) that reference a verification method by its method ID
* or contain an embedded verification method matching the method ID. The method ID is typically a
* fragment of a DID (e.g., `did:example:123#key-1`) that uniquely identifies a verification method
* within the DID document.
*
* The search considers both direct references to verification methods by their IDs and verification
* methods embedded within the verification relationship arrays. It returns an array of
* `DidVerificationRelationship` enums corresponding to the verification relationships that contain
* the specified method ID.
*
* @param params - An object containing input parameters for retrieving verification relationships.
* @param params.didDocument - The DID document to search for verification relationships.
* @param params.methodId - The method ID to search for within the verification relationships.
* @returns An array of `DidVerificationRelationship` enums representing the types of verification
* relationships that reference the specified method ID.
*
* @example
* ```ts
* const didDocument: DidDocument = {
* // ...contents of a DID document...
* };
*
* const relationships = getVerificationRelationshipsById({
* didDocument,
* methodId: 'key-1'
* });
* console.log(relationships);
* // Output might include ['authentication', 'assertionMethod'] if those relationships
* // reference or contain the specified method ID.
* ```
*/
export declare function getVerificationRelationshipsById({ didDocument, methodId }: {
didDocument: DidDocument;
methodId: string;
}): DidVerificationRelationship[];
/**
* Checks if a given object is a {@link DidService}.
*
* A {@link DidService} in the context of DID resources must include the properties `id`, `type`,
* and `serviceEndpoint`. The `serviceEndpoint` can be a `DidServiceEndpoint` or an array of
* `DidServiceEndpoint` objects.
*
* @example
* ```ts
* const service = {
* id: "did:example:123#service-1",
* type: "OidcService",
* serviceEndpoint: "https://example.com/oidc"
* };
*
* if (isDidService(service)) {
* console.log('The object is a DidService');
* } else {
* console.log('The object is not a DidService');
* }
* ```
*
* @param obj - The object to be checked.
* @returns `true` if `obj` is a `DidService`; otherwise, `false`.
*/
export declare function isDidService(obj: unknown): obj is DidService;
/**
* Checks if a given object is a {@link DwnDidService}.
*
* A {@link DwnDidService} is defined as {@link DidService} object with a `type` of
* "DecentralizedWebNode" and `enc` and `sig` properties, where both properties are either strings
* or arrays of strings.
*
* @example
* ```ts
* const didDocument: DidDocument = {
* id: 'did:example:123',
* verificationMethod: [
* {
* id: 'did:example:123#key-1',
* type: 'JsonWebKey2020',
* controller: 'did:example:123',
* publicKeyJwk: { ... }
* },
* {
* id: 'did:example:123#key-2',
* type: 'JsonWebKey2020',
* controller: 'did:example:123',
* publicKeyJwk: { ... }
* }
* ],
* service: [
* {
* id: 'did:example:123#dwn',
* type: 'DecentralizedWebNode',
* serviceEndpoint: 'https://dwn.tbddev.org/dwn0',
* enc: 'did:example:123#key-1',
* sig: 'did:example:123#key-2'
* }
* ]
* };
*
* if (isDwnService(didDocument.service[0])) {
* console.log('The object is a DwnDidService');
* } else {
* console.log('The object is not a DwnDidService');
* }
* ```
*
* @see {@link https://identity.foundation/decentralized-web-node/spec/ | Decentralized Web Node (DWN) Specification}
*
* @param obj - The object to be checked.
* @returns `true` if `obj` is a DwnDidService; otherwise, `false`.
*/
export declare function isDwnDidService(obj: unknown): obj is DwnDidService;
/**
* Checks if a given object is a DID Verification Method.
*
* A {@link DidVerificationMethod} in the context of DID resources must include the properties `id`,
* `type`, and `controller`.
*
* @example
* ```ts
* const resource = {
* id : "did:example:123#0",
* type : "JsonWebKey2020",
* controller : "did:example:123",
* publicKeyJwk : { ... }
* };
*
* if (isDidVerificationMethod(resource)) {
* console.log('The resource is a DidVerificationMethod');
* } else {
* console.log('The resource is not a DidVerificationMethod');
* }
* ```
*
* @param obj - The object to be checked.
* @returns `true` if `obj` is a `DidVerificationMethod`; otherwise, `false`.
*/
export declare function isDidVerificationMethod(obj: unknown): obj is DidVerificationMethod;
/**
* Converts a cryptographic key to a multibase identifier.
*
* @remarks
* This method provides a way to represent a cryptographic key as a multibase identifier.
* It takes a `Uint8Array` representing the key, and either the multicodec code or multicodec name
* as input. The method first adds the multicodec prefix to the key, then encodes it into Base58
* format. Finally, it converts the Base58 encoded key into a multibase identifier.
*
* @example
* ```ts
* const key = new Uint8Array([...]); // Cryptographic key as Uint8Array
* const multibaseId = keyBytesToMultibaseId({ key, multicodecName: 'ed25519-pub' });
* ```
*
* @param params - The parameters for the conversion.
* @returns The multibase identifier as a string.
*/
export declare function keyBytesToMultibaseId({ keyBytes, multicodecCode, multicodecName }: RequireOnly<KeyWithMulticodec, 'keyBytes'>): string;
/**
* Converts a multibase identifier to a cryptographic key.
*
* @remarks
* This function decodes a multibase identifier back into a cryptographic key. It first decodes the
* identifier from multibase format into Base58 format, and then converts it into a `Uint8Array`.
* Afterward, it removes the multicodec prefix, extracting the raw key data along with the
* multicodec code and name.
*
* @example
* ```ts
* const multibaseKeyId = '...'; // Multibase identifier of the key
* const { key, multicodecCode, multicodecName } = multibaseIdToKey({ multibaseKeyId });
* ```
*
* @param params - The parameters for the conversion.
* @param params.multibaseKeyId - The multibase identifier string of the key.
* @returns An object containing the key as a `Uint8Array` and its multicodec code and name.
* @throws `DidError` if the multibase identifier is invalid.
*/
export declare function multibaseIdToKeyBytes({ multibaseKeyId }: {
multibaseKeyId: string;
}): Required<KeyWithMulticodec>;
//# sourceMappingURL=utils.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"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"}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+512
View File
@@ -0,0 +1,512 @@
# Changelog
## [8.0.1] - 2024-01-27
### Fixed
- Explicitly depend on abstract-level for TypeScript ([#241](https://github.com/Level/level/issues/241)) ([`c501868`](https://github.com/Level/level/commit/c501868)) (Hanxx).
## [8.0.0] - 2022-03-25
_If you are upgrading: please see [`UPGRADING.md`](UPGRADING.md)._
### Changed
- **Breaking:** switch to `classic-level` and `browser-level` ([#215](https://github.com/Level/level/issues/215)) ([`ad22b21`](https://github.com/Level/level/commit/ad22b21)) (Vincent Weevers).
## [7.0.1] - 2021-10-02
### Added
- Document new features ([#207](https://github.com/Level/level/issues/207)) ([`ad8f924`](https://github.com/Level/level/commit/ad8f924)) (Vincent Weevers)
### Fixed
- Bump dependencies to prevent dedupe ([`7083ec6`](https://github.com/Level/level/commit/7083ec6)) (Vincent Weevers)
- Clarify `close()` documentation ([#197](https://github.com/Level/level/issues/197)) ([`c82fdbc`](https://github.com/Level/level/commit/c82fdbc)) (Vincent Weevers)
## [7.0.0] - 2021-04-17
_If you are upgrading: please see [`UPGRADING.md`](UPGRADING.md)._
### Changed
- **Breaking:** bump `leveldown` and `level-packager` ([`53bd922`](https://github.com/Level/level/commit/53bd922)) (Vincent Weevers)
- **Breaking:** bump `level-js` from 5.x to 6.x ([#194](https://github.com/Level/level/issues/194)) ([`1f6c603`](https://github.com/Level/level/commit/1f6c603)) (Alex Potsides)
- **Breaking:** modernize syntax ([Level/community#98](https://github.com/Level/community/issues/98)) ([`d001b2c`](https://github.com/Level/level/commit/d001b2c)) (Vincent Weevers)
- Add `files` to `package.json` and remove `.npmignore` ([`329e1f5`](https://github.com/Level/level/commit/329e1f5)) (Vincent Weevers)
### Added
- Document chained batch encoding options ([Level/levelup#633](https://github.com/Level/levelup/issues/633)) ([`0b3c11d`](https://github.com/Level/level/commit/0b3c11d)) (Vincent Weevers)
- Document the `clear` event ([Level/community#79](https://github.com/Level/community/issues/79)) ([`52314bf`](https://github.com/Level/level/commit/52314bf)) (Vincent Weevers)
### Removed
- **Breaking:** drop node 8 ([Level/community#98](https://github.com/Level/community/issues/98)) ([`f8a0047`](https://github.com/Level/level/commit/f8a0047), [`31317a6`](https://github.com/Level/level/commit/31317a6)) (Vincent Weevers)
- Remove legacy range options from README ([Level/community#86](https://github.com/Level/community/issues/86)) ([`e56c6b1`](https://github.com/Level/level/commit/e56c6b1)) (Vincent Weevers)
## [6.0.1] - 2020-03-04
### Changed
- Switch from `opencollective-postinstall` to npm `funding` ([#173](https://github.com/Level/level/issues/173)) ([**@Richienb**](https://github.com/Richienb))
- Upgrade `nyc` devDependency from `^14.0.0` to `^15.0.0` ([#169](https://github.com/Level/level/issues/169)) ([**@vweevers**](https://github.com/vweevers))
- Upgrade `airtap` devDependency from `^2.0.1` to `^3.0.0` ([#171](https://github.com/Level/level/issues/171)) ([**@vweevers**](https://github.com/vweevers))
## [6.0.0] - 2019-10-19
_If you are upgrading: please see [`UPGRADING.md`](UPGRADING.md)._
### Changed
- **Breaking:** upgrade `level-js` from `^4.0.0` to `^5.0.0` ([#158](https://github.com/Level/level/issues/158)) ([**@vweevers**](https://github.com/vweevers))
- Upgrade `hallmark` devDependency from `^0.1.0` to `^2.0.0` ([#152](https://github.com/Level/level/issues/152), [#157](https://github.com/Level/level/issues/157)) ([**@vweevers**](https://github.com/vweevers))
- Upgrade `standard` devDependency from `^12.0.0` to `^14.0.0` ([#151](https://github.com/Level/level/issues/151), [#155](https://github.com/Level/level/issues/155)) ([**@vweevers**](https://github.com/vweevers))
- Upgrade `nyc` devDependency from `^13.2.0` to `^14.0.0` ([#147](https://github.com/Level/level/issues/147)) ([**@vweevers**](https://github.com/vweevers))
### Added
- Document manifest, `iterator()` and `clear()` ([#162](https://github.com/Level/level/issues/162)) ([**@vweevers**](https://github.com/vweevers))
- Add links to `browserify-starter` and `webpack-starter` ([`6ff1802`](https://github.com/Level/level/commit/6ff1802)) ([**@vweevers**](https://github.com/vweevers))
### Fixed
- Bump `leveldown` and `level-packager` to prevent dedupe ([`5efdc82`](https://github.com/Level/level/commit/5efdc82), [`a9656c3`](https://github.com/Level/level/commit/a9656c3), [`97cb31c`](https://github.com/Level/level/commit/97cb31c)) ([**@vweevers**](https://github.com/vweevers))
## [5.0.1] - 2019-03-29
### Fixed
- Temporarily skip `hallmark` test because it breaks CITGM ([#145](https://github.com/Level/level/issues/145)) ([**@vweevers**](https://github.com/vweevers))
## [5.0.0] - 2019-03-29
_If you are upgrading: please see [`UPGRADING.md`](UPGRADING.md)._
### Changed
- Upgrade `leveldown` from `^4.0.0` to `^5.0.0` ([#133](https://github.com/Level/level/issues/133), [#144](https://github.com/Level/level/issues/144)) ([**@vweevers**](https://github.com/vweevers))
- Upgrade `level-packager` from `^3.0.0` to `^5.0.0` ([#113](https://github.com/Level/level/issues/113), [#131](https://github.com/Level/level/issues/131)) ([**@ralphtheninja**](https://github.com/ralphtheninja), [**@vweevers**](https://github.com/vweevers))
- Prefer `var` over `const` in README ([`f032b6c`](https://github.com/Level/level/commit/f032b6c)) ([**@ralphtheninja**](https://github.com/ralphtheninja))
- Upgrade `standard` devDependency from `^11.0.0` to `^12.0.0` ([#118](https://github.com/Level/level/issues/118)) ([**@ralphtheninja**](https://github.com/ralphtheninja))
- Tweak copyright years for less maintenance ([`0b9c8ad`](https://github.com/Level/level/commit/0b9c8ad)) ([**@ralphtheninja**](https://github.com/ralphtheninja))
- Tweak Open Collective documentation ([#137](https://github.com/Level/level/issues/137)) ([**@vweevers**](https://github.com/vweevers))
- Apply common project tweaks ([#136](https://github.com/Level/level/issues/136), [#138](https://github.com/Level/level/issues/138)) ([**@vweevers**](https://github.com/vweevers))
- Add `.travis.yml` and `appveyor.yml` to `.npmignore` ([`7b5c340`](https://github.com/Level/level/commit/7b5c340)) ([**@vweevers**](https://github.com/vweevers))
### Added
- Integrate `level-js` for browser support ([#135](https://github.com/Level/level/issues/135)) ([**@vweevers**](https://github.com/vweevers))
- Add appveyor ([#112](https://github.com/Level/level/issues/112)) ([**@ralphtheninja**](https://github.com/ralphtheninja))
- Enable OSX on Travis ([#111](https://github.com/Level/level/issues/111)) ([**@ralphtheninja**](https://github.com/ralphtheninja))
- Add `nyc` and `coveralls` devDependencies ([#115](https://github.com/Level/level/issues/115), [#143](https://github.com/Level/level/issues/143)) ([**@ralphtheninja**](https://github.com/ralphtheninja), [**@vweevers**](https://github.com/vweevers))
- Add `hallmark` devDependency ([#134](https://github.com/Level/level/issues/134)) ([**@vweevers**](https://github.com/vweevers))
- Add note about Rollup to `README.md` ([#139](https://github.com/Level/level/issues/139)) ([**@vweevers**](https://github.com/vweevers))
### Removed
- Remove node 6 and 9 ([#129](https://github.com/Level/level/issues/129), [`2bf1d3f`](https://github.com/Level/level/commit/2bf1d3f)) ([**@ralphtheninja**](https://github.com/ralphtheninja))
- Remove contributors from `package.json` ([`f37252d`](https://github.com/Level/level/commit/f37252d)) ([**@ralphtheninja**](https://github.com/ralphtheninja))
## [4.0.0] - 2018-05-23
_If you are upgrading: please see [`UPGRADING.md`](UPGRADING.md)._
### Changed
- Update `leveldown` to `^4.0.0` ([**@ralphtheninja**](https://github.com/ralphtheninja))
- Update `level-packager` to `^3.0.0` ([**@ralphtheninja**](https://github.com/ralphtheninja))
- Switch to `opencollective-postinstall` ([**@mateodelnorte**](https://github.com/mateodelnorte))
### Removed
- Remove node 4 from Travis ([**@ralphtheninja**](https://github.com/ralphtheninja))
## [3.0.2] - 2018-05-23
### Changed
- Switch to `opencollective-postinstall` ([**@mateodelnorte**](https://github.com/mateodelnorte))
## [3.0.1] - 2018-05-05
### Added
- Travis: add 10 ([**@ralphtheninja**](https://github.com/ralphtheninja))
### Changed
- Update `standard` to `^11.0.0` ([**@ralphtheninja**](https://github.com/ralphtheninja))
- Fix typo in README ([**@rasmuserik**](https://github.com/rasmuserik))
### Fixed
- Fix postinstall failures with OpenCollective ([**@vweevers**](https://github.com/vweevers))
## [3.0.0] - 2018-02-17
_If you are upgrading: please see [`UPGRADING.md`](UPGRADING.md)._
### Added
- Travis: add 9 ([**@ralphtheninja**](https://github.com/ralphtheninja))
- README: add table of contents ([**@ralphtheninja**](https://github.com/ralphtheninja))
### Changed
- Update `leveldown` to `^3.0.0` ([**@ralphtheninja**](https://github.com/ralphtheninja))
## [2.1.2] - 2018-01-26
### Added
- Add OpenCollective ([**@monkeywithacupcake**](https://github.com/monkeywithacupcake))
### Changed
- README: change Travis badge from png to svg ([**@ralphtheninja**](https://github.com/ralphtheninja))
## [2.1.1] - 2017-12-13
### Changed
- README: document `.errors` property ([**@ralphtheninja**](https://github.com/ralphtheninja))
## [2.1.0] - 2017-12-06
### Changed
- Update `level-packager` to `^2.0.2` ([**@ralphtheninja**](https://github.com/ralphtheninja))
- Update `leveldown` to `^2.1.1` ([**@ralphtheninja**](https://github.com/ralphtheninja))
## [2.0.1] - 2017-11-11
### Changed
- Restore node 4 ([**@vweevers**](https://github.com/vweevers))
## [2.0.0] - 2017-10-17
_If you are upgrading: please see [`UPGRADING.md`](UPGRADING.md)._
### Added
- Add `standard` for linting ([**@ralphtheninja**](https://github.com/ralphtheninja))
- README: copy over docs from `levelup` ([**@ralphtheninja**](https://github.com/ralphtheninja))
- README: add node badge ([**@ralphtheninja**](https://github.com/ralphtheninja))
### Changed
- Update `level-packager` to `~2.0.0` ([**@ralphtheninja**](https://github.com/ralphtheninja))
- Update `leveldown` to `~2.0.0` ([**@ralphtheninja**](https://github.com/ralphtheninja))
## [2.0.0-rc3] - 2017-09-16
### Changed
- Update `level-packager` to `2.0.0-rc3` ([**@ralphtheninja**](https://github.com/ralphtheninja))
- Update `leveldown` to `~1.8.0` ([**@ralphtheninja**](https://github.com/ralphtheninja))
## [2.0.0-rc2] - 2017-09-12
### Changed
- Update `level-packager` to `2.0.0-rc2` ([**@ralphtheninja**](https://github.com/ralphtheninja))
- Update `leveldown` to `~1.7.2` ([**@ralphtheninja**](https://github.com/ralphtheninja))
## [2.0.0-rc1] - 2017-09-06
### Added
- README: add Greenkeeper badge ([**@ralphtheninja**](https://github.com/ralphtheninja))
- Travis: add 8 ([**@ralphtheninja**](https://github.com/ralphtheninja))
### Changed
- Update `level-packager` to `2.0.0-rc1` ([**@ralphtheninja**](https://github.com/ralphtheninja))
### Removed
- Travis: remove 0.12, 4, 5, and 7 ([**@ralphtheninja**](https://github.com/ralphtheninja))
## [1.7.0] - 2017-05-17
### Changed
- Update `leveldown` to `~1.7.0` ([**@ralphtheninja**](https://github.com/ralphtheninja))
## [1.6.0] - 2017-02-06
### Added
- Travis: add 7 ([**@ralphtheninja**](https://github.com/ralphtheninja))
### Changed
- Update copyright year to 2017 ([**@ralphtheninja**](https://github.com/ralphtheninja))
- Update `leveldown` to `~1.6.0` ([**@ralphtheninja**](https://github.com/ralphtheninja))
### Removed
- Travis: remove 0.10 ([**@ralphtheninja**](https://github.com/ralphtheninja))
## [1.5.0] - 2016-10-16
### Added
- Travis: add 6 ([**@ralphtheninja**](https://github.com/ralphtheninja))
### Changed
- Use gcc 4.8 on Travis
- Update `leveldown` to `~1.5.0` ([**@juliangruber**](https://github.com/juliangruber))
### Removed
- Travis: remove 1.0, 1.8, 2 and 3 ([**@ralphtheninja**](https://github.com/ralphtheninja))
## [1.4.0] - 2015-11-27
### Added
- Travis: add 1.0, 2, 3, 4 and 5 ([**@ralphtheninja**](https://github.com/ralphtheninja))
- README: add dependency badge ([**@ralphtheninja**](https://github.com/ralphtheninja))
### Changed
- Update `level-packager` to `~1.2.0` ([**@ralphtheninja**](https://github.com/ralphtheninja))
## [1.3.0] - 2015-07-29
### Changed
- Update `leveldown` to `~1.4.0` ([**@ArtskydJ**](https://github.com/ArtskydJ))
## [1.2.0] - 2015-06-24
### Changed
- Update `level-packager` to `~1.1.0` ([**@timoxley**](https://github.com/timoxley))
- Update `leveldown` to `~1.3.0` ([**@timoxley**](https://github.com/timoxley))
## [1.1.0] - 2015-06-02
### Changed
- Update `leveldown` to `~1.2.2` for prebuilt binaries ([**@ralphtheninja**](https://github.com/ralphtheninja))
## [1.0.0] - 2015-05-19
### Changed
- Update `level-packager` to `~1.0.0` ([**@ralphtheninja**](https://github.com/ralphtheninja))
## [1.0.0-0] - 2015-05-16
### Changed
- Use `nvm` again on Travis ([**@ralphtheninja**](https://github.com/ralphtheninja))
- Moved `CONTRIBUTING.md` and contributors to `level/community` repository ([**@ralphtheninja**](https://github.com/ralphtheninja))
- Use `level-packager@next` ([**@ralphtheninja**](https://github.com/ralphtheninja))
- Update `leveldown` to `~1.0.6` ([**@ralphtheninja**](https://github.com/ralphtheninja))
## [0.19.1] - 2015-05-05
### Changed
- Use `n` instead of `nvm` on Travis for iojs support on native modules ([**@ralphtheninja**](https://github.com/ralphtheninja))
## [0.19.0] - 2015-05-05
### Changed
- Switch to plain MIT license ([**@andrewrk**](https://github.com/andrewrk))
- README: update nodeico badge ([**@rvagg**](https://github.com/rvagg))
- README: update logo and copyright ([**@ralphtheninja**](https://github.com/ralphtheninja))
- Update `level-packager` to `~0.19.0` ([**@ralphtheninja**](https://github.com/ralphtheninja))
## [0.18.0] - 2013-11-18
### Added
- Add Travis ([**@rvagg**](https://github.com/rvagg))
### Changed
- Update `level-packager` to `~0.18.0` ([**@rvagg**](https://github.com/rvagg))
- Update `leveldown` to `~0.10.0` ([**@rvagg**](https://github.com/rvagg))
## [0.17.0] - 2013-10-01
_0.17.0 and 0.17.0-1 are listed out of order here, due to 0.17.0-1 not adhering to the semver rules that we follow today._
### Changed
- Update `levelup` to `~0.17.0` ([**@rvagg**](https://github.com/rvagg))
- Update `leveldown` to `~0.9.0` ([**@rvagg**](https://github.com/rvagg))
## [0.17.0-1] - 2013-10-09
### Changed
- Use `level-packager` instead of `levelup` ([**@rvagg**](https://github.com/rvagg))
- Run tests in `level-packager` using `tape` ([**@rvagg**](https://github.com/rvagg))
## [0.16.0] - 2013-09-10
### Added
- Add [**@substack**](https://github.com/substack) to contributors ([**@rvagg**](https://github.com/rvagg))
### Changed
- Update `levelup` to `~0.16.0` ([**@rvagg**](https://github.com/rvagg))
- Update repository and homepage in `package.json` ([**@rvagg**](https://github.com/rvagg))
## [0.15.0] - 2013-08-26
### Changed
- README: tweaks ([**@rvagg**](https://github.com/rvagg))
- Update `levelup` to `~0.15.0` ([**@rvagg**](https://github.com/rvagg))
- Update `leveldown` to `~0.8.0` ([**@rvagg**](https://github.com/rvagg))
## [0.14.0] - 2013-08-19
### Added
- README: add npm downloads badge ([**@rvagg**](https://github.com/rvagg))
### Changed
- Update `levelup` to `~0.14.0` ([**@rvagg**](https://github.com/rvagg))
## [0.13.0] - 2013-08-11
### Changed
- Update `levelup` to `~0.13.0` ([**@rvagg**](https://github.com/rvagg))
- Update `leveldown` to `~0.7.0` ([**@rvagg**](https://github.com/rvagg))
## [0.12.0] - 2013-07-25
### Changed
- Update `levelup` to `~0.12.0` ([**@rvagg**](https://github.com/rvagg))
- Update `leveldown` to `~0.6.2` ([**@rvagg**](https://github.com/rvagg))
## [0.11.0] - 2013-07-17
### Added
- Add [**@pgte**](https://github.com/pgte) to contributors ([**@rvagg**](https://github.com/rvagg))
- README: add npm badge ([**@rvagg**](https://github.com/rvagg))
### Changed
- Update `levelup` to `~0.11.0` ([**@rvagg**](https://github.com/rvagg))
## [0.10.0] - 2013-06-14
### Changed
- Update `levelup` to `~0.10.0` ([**@rvagg**](https://github.com/rvagg))
- Update `leveldown` to `~0.6.0` ([**@rvagg**](https://github.com/rvagg))
## [0.9.0] - 2013-05-27
### Changed
- Update `levelup` to `~0.9.0` ([**@rvagg**](https://github.com/rvagg))
- Update `leveldown` to `~0.5.0` ([**@rvagg**](https://github.com/rvagg))
## [0.8.0] - 2013-05-19
:seedling: Initial release.
[8.0.1]: https://github.com/Level/level/releases/tag/v8.0.1
[8.0.0]: https://github.com/Level/level/releases/tag/v8.0.0
[7.0.1]: https://github.com/Level/level/releases/tag/v7.0.1
[7.0.0]: https://github.com/Level/level/releases/tag/v7.0.0
[6.0.1]: https://github.com/Level/level/releases/tag/v6.0.1
[6.0.0]: https://github.com/Level/level/releases/tag/v6.0.0
[5.0.1]: https://github.com/Level/level/releases/tag/v5.0.1
[5.0.0]: https://github.com/Level/level/releases/tag/v5.0.0
[4.0.0]: https://github.com/Level/level/releases/tag/v4.0.0
[3.0.2]: https://github.com/Level/level/releases/tag/v3.0.2
[3.0.1]: https://github.com/Level/level/releases/tag/v3.0.1
[3.0.0]: https://github.com/Level/level/releases/tag/v3.0.0
[2.1.2]: https://github.com/Level/level/releases/tag/v2.1.2
[2.1.1]: https://github.com/Level/level/releases/tag/v2.1.1
[2.1.0]: https://github.com/Level/level/releases/tag/v2.1.0
[2.0.1]: https://github.com/Level/level/releases/tag/v2.0.1
[2.0.0]: https://github.com/Level/level/releases/tag/v2.0.0
[2.0.0-rc3]: https://github.com/Level/level/releases/tag/v2.0.0-rc3
[2.0.0-rc2]: https://github.com/Level/level/releases/tag/v2.0.0-rc2
[2.0.0-rc1]: https://github.com/Level/level/releases/tag/v2.0.0-rc1
[1.7.0]: https://github.com/Level/level/releases/tag/v1.7.0
[1.6.0]: https://github.com/Level/level/releases/tag/v1.6.0
[1.5.0]: https://github.com/Level/level/releases/tag/v1.5.0
[1.4.0]: https://github.com/Level/level/releases/tag/v1.4.0
[1.3.0]: https://github.com/Level/level/releases/tag/v1.3.0
[1.2.0]: https://github.com/Level/level/releases/tag/v1.2.0
[1.1.0]: https://github.com/Level/level/releases/tag/v1.1.0
[1.0.0]: https://github.com/Level/level/releases/tag/v1.0.0
[1.0.0-0]: https://github.com/Level/level/releases/tag/v1.0.0-0
[0.19.1]: https://github.com/Level/level/releases/tag/v0.19.1
[0.19.0]: https://github.com/Level/level/releases/tag/v0.19.0
[0.18.0]: https://github.com/Level/level/releases/tag/0.18.0
[0.17.0]: https://github.com/Level/level/releases/tag/0.17.0
[0.17.0-1]: https://github.com/Level/level/releases/tag/0.17.0-1
[0.16.0]: https://github.com/Level/level/releases/tag/0.16.0
[0.15.0]: https://github.com/Level/level/releases/tag/0.15.0
[0.14.0]: https://github.com/Level/level/releases/tag/0.14.0
[0.13.0]: https://github.com/Level/level/releases/tag/0.13.0
[0.12.0]: https://github.com/Level/level/releases/tag/0.12.0
[0.11.0]: https://github.com/Level/level/releases/tag/0.11.0
[0.10.0]: https://github.com/Level/level/releases/tag/0.10.0
[0.9.0]: https://github.com/Level/level/releases/tag/0.9.0
[0.8.0]: https://github.com/Level/level/releases/tag/0.8.0
+21
View File
@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright © 2013 Rod Vagg and the contributors to level.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+620
View File
@@ -0,0 +1,620 @@
# level
**Universal [`abstract-level`](https://github.com/Level/abstract-level) database for Node.js and browsers.** This is a convenience package that exports [`classic-level`](https://github.com/Level/classic-level) in Node.js and [`browser-level`](https://github.com/Level/browser-level) in browsers, making it an ideal entry point to start creating lexicographically sorted key-value databases.
> :pushpin: Which module should I use? What is `abstract-level`? Head over to the [FAQ](https://github.com/Level/community#faq).
[![level badge][level-badge]](https://github.com/Level/awesome)
[![npm](https://img.shields.io/npm/v/level.svg)](https://www.npmjs.com/package/level)
[![Node version](https://img.shields.io/node/v/level.svg)](https://www.npmjs.com/package/level)
[![Test](https://img.shields.io/github/actions/workflow/status/Level/level/test.yml?branch=master&label=test)](https://github.com/Level/level/actions/workflows/test.yml)
[![Coverage](https://img.shields.io/codecov/c/github/Level/level?label=\&logo=codecov\&logoColor=fff)](https://codecov.io/gh/Level/level)
[![Standard](https://img.shields.io/badge/standard-informational?logo=javascript\&logoColor=fff)](https://standardjs.com)
[![Common Changelog](https://common-changelog.org/badge.svg)](https://common-changelog.org)
[![Community](https://img.shields.io/badge/community-join-%2370B99E?logo=github)](https://github.com/Level/community/issues)
[![Donate](https://img.shields.io/badge/donate-orange?logo=open-collective\&logoColor=fff)](https://opencollective.com/level)
## Table of Contents
<details><summary>Click to expand</summary>
- [Usage](#usage)
- [Install](#install)
- [Supported Platforms](#supported-platforms)
- [API](#api)
- [`db = new Level(location[, options])`](#db--new-levellocation-options)
- [`db.status`](#dbstatus)
- [`db.open([callback])`](#dbopencallback)
- [`db.close([callback])`](#dbclosecallback)
- [`db.supports`](#dbsupports)
- [`db.get(key[, options][, callback])`](#dbgetkey-options-callback)
- [`db.getMany(keys[, options][, callback])`](#dbgetmanykeys-options-callback)
- [`db.put(key, value[, options][, callback])`](#dbputkey-value-options-callback)
- [`db.del(key[, options][, callback])`](#dbdelkey-options-callback)
- [`db.batch(operations[, options][, callback])`](#dbbatchoperations-options-callback)
- [`chainedBatch = db.batch()`](#chainedbatch--dbbatch)
- [`iterator = db.iterator([options])`](#iterator--dbiteratoroptions)
- [`keyIterator = db.keys([options])`](#keyiterator--dbkeysoptions)
- [`valueIterator = db.values([options])`](#valueiterator--dbvaluesoptions)
- [`db.clear([options][, callback])`](#dbclearoptions-callback)
- [`sublevel = db.sublevel(name[, options])`](#sublevel--dbsublevelname-options)
- [`chainedBatch`](#chainedbatch)
- [`chainedBatch.put(key, value[, options])`](#chainedbatchputkey-value-options)
- [`chainedBatch.del(key[, options])`](#chainedbatchdelkey-options)
- [`chainedBatch.clear()`](#chainedbatchclear)
- [`chainedBatch.write([options][, callback])`](#chainedbatchwriteoptions-callback)
- [`chainedBatch.close([callback])`](#chainedbatchclosecallback)
- [`chainedBatch.length`](#chainedbatchlength)
- [`chainedBatch.db`](#chainedbatchdb)
- [`iterator`](#iterator)
- [`for await...of iterator`](#for-awaitof-iterator)
- [`iterator.next([callback])`](#iteratornextcallback)
- [`iterator.nextv(size[, options][, callback])`](#iteratornextvsize-options-callback)
- [`iterator.all([options][, callback])`](#iteratoralloptions-callback)
- [`iterator.seek(target[, options])`](#iteratorseektarget-options)
- [`iterator.close([callback])`](#iteratorclosecallback)
- [`iterator.db`](#iteratordb)
- [`iterator.count`](#iteratorcount)
- [`iterator.limit`](#iteratorlimit)
- [`keyIterator`](#keyiterator)
- [`valueIterator`](#valueiterator)
- [`sublevel`](#sublevel)
- [`sublevel.prefix`](#sublevelprefix)
- [`sublevel.db`](#subleveldb)
- [Contributing](#contributing)
- [Donate](#donate)
- [License](#license)
</details>
## Usage
_If you are upgrading: please see [`UPGRADING.md`](UPGRADING.md)._
```js
const { Level } = require('level')
// Create a database
const db = new Level('example', { valueEncoding: 'json' })
// Add an entry with key 'a' and value 1
await db.put('a', 1)
// Add multiple entries
await db.batch([{ type: 'put', key: 'b', value: 2 }])
// Get value of key 'a': 1
const value = await db.get('a')
// Iterate entries with keys that are greater than 'a'
for await (const [key, value] of db.iterator({ gt: 'a' })) {
console.log(value) // 2
}
```
All asynchronous methods also support callbacks.
<details><summary>Callback example</summary>
```js
db.put('a', { x: 123 }, function (err) {
if (err) throw err
db.get('a', function (err, value) {
console.log(value) // { x: 123 }
})
})
```
</details>
TypeScript type declarations are included and cover the methods that are common between `classic-level` and `browser-level`. Usage from TypeScript requires generic type parameters.
<details><summary>TypeScript example</summary>
```ts
// Specify types of keys and values (any, in the case of json).
// The generic type parameters default to Level<string, string>.
const db = new Level<string, any>('./db', { valueEncoding: 'json' })
// All relevant methods then use those types
await db.put('a', { x: 123 })
// Specify different types when overriding encoding per operation
await db.get<string, string>('a', { valueEncoding: 'utf8' })
// Though in some cases TypeScript can infer them
await db.get('a', { valueEncoding: db.valueEncoding('utf8') })
// It works the same for sublevels
const abc = db.sublevel('abc')
const xyz = db.sublevel<string, any>('xyz', { valueEncoding: 'json' })
```
</details>
## Install
With [npm](https://npmjs.org) do:
```bash
npm install level
```
For use in browsers, this package is best used with [`browserify`](https://github.com/browserify/browserify), [`webpack`](https://webpack.js.org/), [`rollup`](https://rollupjs.org/) or similar bundlers. For a quick start, visit [`browserify-starter`](https://github.com/Level/browserify-starter) or [`webpack-starter`](https://github.com/Level/webpack-starter).
## Supported Platforms
At the time of writing, `level` works in Node.js 12+ and Electron 5+ on Linux, Mac OS, Windows and FreeBSD, including any future Node.js and Electron release thanks to [Node-API](https://nodejs.org/api/n-api.html), including ARM platforms like Raspberry Pi and Android, as well as in Chrome, Firefox, Edge, Safari, iOS Safari and Chrome for Android. For details, see [Supported Platforms](https://github.com/Level/classic-level#supported-platforms) of `classic-level` and [Browser Support](https://github.com/Level/browser-level#browser-support) of `browser-level`.
Binary keys and values are supported across the board.
## API
The API of `level` follows that of [`abstract-level`](https://github.com/Level/abstract-level). The documentation below covers it all except for [Encodings](https://github.com/Level/abstract-level#encodings), [Events](https://github.com/Level/abstract-level#events) and [Errors](https://github.com/Level/abstract-level#errors) which are exclusively documented in `abstract-level`. For options and additional methods specific to [`classic-level`](https://github.com/Level/classic-level) and [`browser-level`](https://github.com/Level/browser-level), please see their respective READMEs.
An `abstract-level` and thus `level` database is at its core a [key-value database](https://en.wikipedia.org/wiki/Key%E2%80%93value_database). A key-value pair is referred to as an _entry_ here and typically returned as an array, comparable to [`Object.entries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries).
### `db = new Level(location[, options])`
Create a new database or open an existing database. The `location` argument must be a directory path (relative or absolute) where LevelDB will store its files, or in browsers, the name of the [`IDBDatabase`](https://developer.mozilla.org/en-US/docs/Web/API/IDBDatabase) to be opened.
The optional `options` object may contain:
- `keyEncoding` (string or object, default `'utf8'`): encoding to use for keys
- `valueEncoding` (string or object, default `'utf8'`): encoding to use for values.
See [Encodings](https://github.com/Level/abstract-level#encodings) for a full description of these options. Other `options` (except `passive`) are forwarded to `db.open()` which is automatically called in a next tick after the constructor returns. Any read & write operations are queued internally until the database has finished opening. If opening fails, those queued operations will yield errors.
### `db.status`
Read-only getter that returns a string reflecting the current state of the database:
- `'opening'` - waiting for the database to be opened
- `'open'` - successfully opened the database
- `'closing'` - waiting for the database to be closed
- `'closed'` - successfully closed the database.
### `db.open([callback])`
Open the database. The `callback` function will be called with no arguments when successfully opened, or with a single error argument if opening failed. If no callback is provided, a promise is returned. Options passed to `open()` take precedence over options passed to the database constructor. The `createIfMissing` and `errorIfExists` options are not supported by [`browser-level`](https://github.com/Level/browser-level).
The optional `options` object may contain:
- `createIfMissing` (boolean, default: `true`): If `true`, create an empty database if one doesn't already exist. If `false` and the database doesn't exist, opening will fail.
- `errorIfExists` (boolean, default: `false`): If `true` and the database already exists, opening will fail.
- `passive` (boolean, default: `false`): Wait for, but do not initiate, opening of the database.
It's generally not necessary to call `open()` because it's automatically called by the database constructor. It may however be useful to capture an error from failure to open, that would otherwise not surface until another method like `db.get()` is called. It's also possible to reopen the database after it has been closed with [`close()`](#dbclosecallback). Once `open()` has then been called, any read & write operations will again be queued internally until opening has finished.
The `open()` and `close()` methods are idempotent. If the database is already open, the `callback` will be called in a next tick. If opening is already in progress, the `callback` will be called when that has finished. If closing is in progress, the database will be reopened once closing has finished. Likewise, if `close()` is called after `open()`, the database will be closed once opening has finished and the prior `open()` call will receive an error.
### `db.close([callback])`
Close the database. The `callback` function will be called with no arguments if closing succeeded or with a single `error` argument if closing failed. If no callback is provided, a promise is returned.
A database may have associated resources like file handles and locks. When the database is no longer needed (for the remainder of a program) it's recommended to call `db.close()` to free up resources.
After `db.close()` has been called, no further read & write operations are allowed unless and until `db.open()` is called again. For example, `db.get(key)` will yield an error with code [`LEVEL_DATABASE_NOT_OPEN`](https://github.com/Level/abstract-level#errors). Any unclosed iterators or chained batches will be closed by `db.close()` and can then no longer be used even when `db.open()` is called again.
### `db.supports`
A [manifest](https://github.com/Level/supports) describing the features supported by this database. Might be used like so:
```js
if (!db.supports.permanence) {
throw new Error('Persistent storage is required')
}
```
### `db.get(key[, options][, callback])`
Get a value from the database by `key`. The optional `options` object may contain:
- `keyEncoding`: custom key encoding for this operation, used to encode the `key`.
- `valueEncoding`: custom value encoding for this operation, used to decode the value.
The `callback` function will be called with an error if the operation failed. If the key was not found, the error will have code [`LEVEL_NOT_FOUND`](https://github.com/Level/abstract-level#errors). If successful the first argument will be `null` and the second argument will be the value. If no callback is provided, a promise is returned.
### `db.getMany(keys[, options][, callback])`
Get multiple values from the database by an array of `keys`. The optional `options` object may contain:
- `keyEncoding`: custom key encoding for this operation, used to encode the `keys`.
- `valueEncoding`: custom value encoding for this operation, used to decode values.
The `callback` function will be called with an error if the operation failed. If successful the first argument will be `null` and the second argument will be an array of values with the same order as `keys`. If a key was not found, the relevant value will be `undefined`. If no callback is provided, a promise is returned.
### `db.put(key, value[, options][, callback])`
Add a new entry or overwrite an existing entry. The optional `options` object may contain:
- `keyEncoding`: custom key encoding for this operation, used to encode the `key`.
- `valueEncoding`: custom value encoding for this operation, used to encode the `value`.
The `callback` function will be called with no arguments if the operation was successful or with an error if it failed. If no callback is provided, a promise is returned.
### `db.del(key[, options][, callback])`
Delete an entry by `key`. The optional `options` object may contain:
- `keyEncoding`: custom key encoding for this operation, used to encode the `key`.
The `callback` function will be called with no arguments if the operation was successful or with an error if it failed. If no callback is provided, a promise is returned.
### `db.batch(operations[, options][, callback])`
Perform multiple _put_ and/or _del_ operations in bulk. The `operations` argument must be an array containing a list of operations to be executed sequentially, although as a whole they are performed as an atomic operation.
Each operation must be an object with at least a `type` property set to either `'put'` or `'del'`. If the `type` is `'put'`, the operation must have `key` and `value` properties. It may optionally have `keyEncoding` and / or `valueEncoding` properties to encode keys or values with a custom encoding for just that operation. If the `type` is `'del'`, the operation must have a `key` property and may optionally have a `keyEncoding` property.
An operation of either type may also have a `sublevel` property, to prefix the key of the operation with the prefix of that sublevel. This allows atomically committing data to multiple sublevels. Keys and values will be encoded by the sublevel, to the same effect as a `sublevel.batch(..)` call. In the following example, the first `value` will be encoded with `'json'` rather than the default encoding of `db`:
```js
const people = db.sublevel('people', { valueEncoding: 'json' })
const nameIndex = db.sublevel('names')
await db.batch([{
type: 'put',
sublevel: people,
key: '123',
value: {
name: 'Alice'
}
}, {
type: 'put',
sublevel: nameIndex,
key: 'Alice',
value: '123'
}])
```
The optional `options` object may contain:
- `keyEncoding`: custom key encoding for this batch, used to encode keys.
- `valueEncoding`: custom value encoding for this batch, used to encode values.
Encoding properties on individual operations take precedence. In the following example, the first value will be encoded with the `'utf8'` encoding and the second with `'json'`.
```js
await db.batch([
{ type: 'put', key: 'a', value: 'foo' },
{ type: 'put', key: 'b', value: 123, valueEncoding: 'json' }
], { valueEncoding: 'utf8' })
```
The `callback` function will be called with no arguments if the batch was successful or with an error if it failed. If no callback is provided, a promise is returned.
### `chainedBatch = db.batch()`
Create a [chained batch](#chainedbatch), when `batch()` is called with zero arguments. A chained batch can be used to build and eventually commit an atomic batch of operations. Depending on how it's used, it is possible to obtain greater performance with this form of `batch()`. On `browser-level` however, it is just sugar.
```js
await db.batch()
.del('bob')
.put('alice', 361)
.put('kim', 220)
.write()
```
### `iterator = db.iterator([options])`
Create an [iterator](#iterator). The optional `options` object may contain the following _range options_ to control the range of entries to be iterated:
- `gt` (greater than) or `gte` (greater than or equal): define the lower bound of the range to be iterated. Only entries where the key is greater than (or equal to) this option will be included in the range. When `reverse` is true the order will be reversed, but the entries iterated will be the same.
- `lt` (less than) or `lte` (less than or equal): define the higher bound of the range to be iterated. Only entries where the key is less than (or equal to) this option will be included in the range. When `reverse` is true the order will be reversed, but the entries iterated will be the same.
- `reverse` (boolean, default: `false`): iterate entries in reverse order. Beware that a reverse seek can be slower than a forward seek.
- `limit` (number, default: `Infinity`): limit the number of entries yielded. This number represents a _maximum_ number of entries and will not be reached if the end of the range is reached first. A value of `Infinity` or `-1` means there is no limit. When `reverse` is true the entries with the highest keys will be returned instead of the lowest keys.
The `gte` and `lte` range options take precedence over `gt` and `lt` respectively. If no range options are provided, the iterator will visit all entries of the database, starting at the lowest key and ending at the highest key (unless `reverse` is true). In addition to range options, the `options` object may contain:
- `keys` (boolean, default: `true`): whether to return the key of each entry. If set to `false`, the iterator will yield keys that are `undefined`. Prefer to use `db.keys()` instead.
- `values` (boolean, default: `true`): whether to return the value of each entry. If set to `false`, the iterator will yield values that are `undefined`. Prefer to use `db.values()` instead.
- `keyEncoding`: custom key encoding for this iterator, used to encode range options, to encode `seek()` targets and to decode keys.
- `valueEncoding`: custom value encoding for this iterator, used to decode values.
> :pushpin: To instead consume data using streams, see [`level-read-stream`](https://github.com/Level/read-stream) and [`level-web-stream`](https://github.com/Level/web-stream).
### `keyIterator = db.keys([options])`
Create a [key iterator](#keyiterator), having the same interface as `db.iterator()` except that it yields keys instead of entries. If only keys are needed, using `db.keys()` may increase performance because values won't have to fetched, copied or decoded. Options are the same as for `db.iterator()` except that `db.keys()` does not take `keys`, `values` and `valueEncoding` options.
```js
// Iterate lazily
for await (const key of db.keys({ gt: 'a' })) {
console.log(key)
}
// Get all at once. Setting a limit is recommended.
const keys = await db.keys({ gt: 'a', limit: 10 }).all()
```
### `valueIterator = db.values([options])`
Create a [value iterator](#valueiterator), having the same interface as `db.iterator()` except that it yields values instead of entries. If only values are needed, using `db.values()` may increase performance because keys won't have to fetched, copied or decoded. Options are the same as for `db.iterator()` except that `db.values()` does not take `keys` and `values` options. Note that it _does_ take a `keyEncoding` option, relevant for the encoding of range options.
```js
// Iterate lazily
for await (const value of db.values({ gt: 'a' })) {
console.log(value)
}
// Get all at once. Setting a limit is recommended.
const values = await db.values({ gt: 'a', limit: 10 }).all()
```
### `db.clear([options][, callback])`
Delete all entries or a range. Not guaranteed to be atomic. Accepts the following options (with the same rules as on iterators):
- `gt` (greater than) or `gte` (greater than or equal): define the lower bound of the range to be deleted. Only entries where the key is greater than (or equal to) this option will be included in the range. When `reverse` is true the order will be reversed, but the entries deleted will be the same.
- `lt` (less than) or `lte` (less than or equal): define the higher bound of the range to be deleted. Only entries where the key is less than (or equal to) this option will be included in the range. When `reverse` is true the order will be reversed, but the entries deleted will be the same.
- `reverse` (boolean, default: `false`): delete entries in reverse order. Only effective in combination with `limit`, to delete the last N entries.
- `limit` (number, default: `Infinity`): limit the number of entries to be deleted. This number represents a _maximum_ number of entries and will not be reached if the end of the range is reached first. A value of `Infinity` or `-1` means there is no limit. When `reverse` is true the entries with the highest keys will be deleted instead of the lowest keys.
- `keyEncoding`: custom key encoding for this operation, used to encode range options.
The `gte` and `lte` range options take precedence over `gt` and `lt` respectively. If no options are provided, all entries will be deleted. The `callback` function will be called with no arguments if the operation was successful or with an error if it failed. If no callback is provided, a promise is returned.
### `sublevel = db.sublevel(name[, options])`
Create a [sublevel](#sublevel) that has the same interface as `db` (except for additional methods specific to `classic-level` or `browser-level`) and prefixes the keys of operations before passing them on to `db`. The `name` argument is required and must be a string.
```js
const example = db.sublevel('example')
await example.put('hello', 'world')
await db.put('a', '1')
// Prints ['hello', 'world']
for await (const [key, value] of example.iterator()) {
console.log([key, value])
}
```
Sublevels effectively separate a database into sections. Think SQL tables, but evented, ranged and real-time! Each sublevel is an `AbstractLevel` instance with its own keyspace, [events](https://github.com/Level/abstract-level#events) and [encodings](https://github.com/Level/abstract-level#encodings). For example, it's possible to have one sublevel with `'buffer'` keys and another with `'utf8'` keys. The same goes for values. Like so:
```js
db.sublevel('one', { valueEncoding: 'json' })
db.sublevel('two', { keyEncoding: 'buffer' })
```
An own keyspace means that `sublevel.iterator()` only includes entries of that sublevel, `sublevel.clear()` will only delete entries of that sublevel, and so forth. Range options get prefixed too.
Fully qualified keys (as seen from the parent database) take the form of `prefix + key` where `prefix` is `separator + name + separator`. If `name` is empty, the effective prefix is two separators. Sublevels can be nested: if `db` is itself a sublevel then the effective prefix is a combined prefix, e.g. `'!one!!two!'`. Note that a parent database will see its own keys as well as keys of any nested sublevels:
```js
// Prints ['!example!hello', 'world'] and ['a', '1']
for await (const [key, value] of db.iterator()) {
console.log([key, value])
}
```
> :pushpin: The key structure is equal to that of [`subleveldown`](https://github.com/Level/subleveldown) which offered sublevels before they were built-in to `abstract-level`. This means that an `abstract-level` sublevel can read sublevels previously created with (and populated by) `subleveldown`.
Internally, sublevels operate on keys that are either a string, Buffer or Uint8Array, depending on parent database and choice of encoding. Which is to say: binary keys are fully supported. The `name` must however always be a string and can only contain ASCII characters.
The optional `options` object may contain:
- `separator` (string, default: `'!'`): Character for separating sublevel names from user keys and each other. Must sort before characters used in `name`. An error will be thrown if that's not the case.
- `keyEncoding` (string or object, default `'utf8'`): encoding to use for keys
- `valueEncoding` (string or object, default `'utf8'`): encoding to use for values.
The `keyEncoding` and `valueEncoding` options are forwarded to the `AbstractLevel` constructor and work the same, as if a new, separate database was created. They default to `'utf8'` regardless of the encodings configured on `db`. Other options are forwarded too but `abstract-level` (and therefor `level`) has no relevant options at the time of writing. For example, setting the `createIfMissing` option will have no effect. Why is that?
Like regular databases, sublevels open themselves but they do not affect the state of the parent database. This means a sublevel can be individually closed and (re)opened. If the sublevel is created while the parent database is opening, it will wait for that to finish. If the parent database is closed, then opening the sublevel will fail and subsequent operations on the sublevel will yield errors with code [`LEVEL_DATABASE_NOT_OPEN`](https://github.com/Level/abstract-level#errors).
### `chainedBatch`
#### `chainedBatch.put(key, value[, options])`
Queue a `put` operation on this batch, not committed until `write()` is called. This will throw a [`LEVEL_INVALID_KEY`](https://github.com/Level/abstract-level#errors) or [`LEVEL_INVALID_VALUE`](https://github.com/Level/abstract-level#errors) error if `key` or `value` is invalid. The optional `options` object may contain:
- `keyEncoding`: custom key encoding for this operation, used to encode the `key`.
- `valueEncoding`: custom value encoding for this operation, used to encode the `value`.
- `sublevel` (sublevel instance): act as though the `put` operation is performed on the given sublevel, to similar effect as `sublevel.batch().put(key, value)`. This allows atomically committing data to multiple sublevels. The `key` will be prefixed with the `prefix` of the sublevel, and the `key` and `value` will be encoded by the sublevel (using the default encodings of the sublevel unless `keyEncoding` and / or `valueEncoding` are provided).
#### `chainedBatch.del(key[, options])`
Queue a `del` operation on this batch, not committed until `write()` is called. This will throw a [`LEVEL_INVALID_KEY`](https://github.com/Level/abstract-level#errors) error if `key` is invalid. The optional `options` object may contain:
- `keyEncoding`: custom key encoding for this operation, used to encode the `key`.
- `sublevel` (sublevel instance): act as though the `del` operation is performed on the given sublevel, to similar effect as `sublevel.batch().del(key)`. This allows atomically committing data to multiple sublevels. The `key` will be prefixed with the `prefix` of the sublevel, and the `key` will be encoded by the sublevel (using the default key encoding of the sublevel unless `keyEncoding` is provided).
#### `chainedBatch.clear()`
Clear all queued operations on this batch.
#### `chainedBatch.write([options][, callback])`
Commit the queued operations for this batch. All operations will be written atomically, that is, they will either all succeed or fail with no partial commits.
There are no `options` (that are common between `classic-level` and `browser-level`). Note that `write()` does not take encoding options. Those can only be set on `put()` and `del()`.
The `callback` function will be called with no arguments if the batch was successful or with an error if it failed. If no callback is provided, a promise is returned.
After `write()` or `close()` has been called, no further operations are allowed.
#### `chainedBatch.close([callback])`
Free up underlying resources. This should be done even if the chained batch has zero queued operations. Automatically called by `write()` so normally not necessary to call, unless the intent is to discard a chained batch without committing it. The `callback` function will be called with no arguments. If no callback is provided, a promise is returned. Closing the batch is an idempotent operation, such that calling `close()` more than once is allowed and makes no difference.
#### `chainedBatch.length`
The number of queued operations on the current batch.
#### `chainedBatch.db`
A reference to the database that created this chained batch.
### `iterator`
An iterator allows one to lazily read a range of entries stored in the database. The entries will be sorted by keys in [lexicographic order](https://en.wikipedia.org/wiki/Lexicographic_order) (in other words: byte order) which in short means key `'a'` comes before `'b'` and key `'10'` comes before `'2'`.
A `classic-level` iterator reads from a snapshot of the database, created at the time `db.iterator()` was called. This means the iterator will not see the data of simultaneous write operations. A `browser-level` iterator does not offer such guarantees, as is indicated by `db.supports.snapshots`. That property will be true in Node.js and false in browsers.
Iterators can be consumed with [`for await...of`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of) and `iterator.all()`, or by manually calling `iterator.next()` or `nextv()` in succession. In the latter case, `iterator.close()` must always be called. In contrast, finishing, throwing, breaking or returning from a `for await...of` loop automatically calls `iterator.close()`, as does `iterator.all()`.
An iterator reaches its natural end in the following situations:
- The end of the database has been reached
- The end of the range has been reached
- The last `iterator.seek()` was out of range.
An iterator keeps track of calls that are in progress. It doesn't allow concurrent `next()`, `nextv()` or `all()` calls (including a combination thereof) and will throw an error with code [`LEVEL_ITERATOR_BUSY`](https://github.com/Level/abstract-level#errors) if that happens:
```js
// Not awaited and no callback provided
iterator.next()
try {
// Which means next() is still in progress here
iterator.all()
} catch (err) {
console.log(err.code) // 'LEVEL_ITERATOR_BUSY'
}
```
#### `for await...of iterator`
Yields entries, which are arrays containing a `key` and `value`. The type of `key` and `value` depends on the options passed to `db.iterator()`.
```js
try {
for await (const [key, value] of db.iterator()) {
console.log(key)
}
} catch (err) {
console.error(err)
}
```
#### `iterator.next([callback])`
Advance to the next entry and yield that entry. If an error occurs, the `callback` function will be called with an error. Otherwise, the `callback` receives `null`, a `key` and a `value`. The type of `key` and `value` depends on the options passed to `db.iterator()`. If the iterator has reached its natural end, both `key` and `value` will be `undefined`.
If no callback is provided, a promise is returned for either an entry array (containing a `key` and `value`) or `undefined` if the iterator reached its natural end.
**Note:** `iterator.close()` must always be called once there's no intention to call `next()` or `nextv()` again. Even if such calls yielded an error and even if the iterator reached its natural end. Not closing the iterator will result in memory leaks and may also affect performance of other operations if many iterators are unclosed and each is holding a snapshot of the database.
#### `iterator.nextv(size[, options][, callback])`
Advance repeatedly and get at most `size` amount of entries in a single call. Can be faster than repeated `next()` calls. The `size` argument must be an integer and has a soft minimum of 1. There are no `options` at the moment.
If an error occurs, the `callback` function will be called with an error. Otherwise, the `callback` receives `null` and an array of entries, where each entry is an array containing a key and value. The natural end of the iterator will be signaled by yielding an empty array. If no callback is provided, a promise is returned.
```js
const iterator = db.iterator()
while (true) {
const entries = await iterator.nextv(100)
if (entries.length === 0) {
break
}
for (const [key, value] of entries) {
// ..
}
}
await iterator.close()
```
#### `iterator.all([options][, callback])`
Advance repeatedly and get all (remaining) entries as an array, automatically closing the iterator. Assumes that those entries fit in memory. If that's not the case, instead use `next()`, `nextv()` or `for await...of`. There are no `options` at the moment. If an error occurs, the `callback` function will be called with an error. Otherwise, the `callback` receives `null` and an array of entries, where each entry is an array containing a key and value. If no callback is provided, a promise is returned.
```js
const entries = await db.iterator({ limit: 100 }).all()
for (const [key, value] of entries) {
// ..
}
```
#### `iterator.seek(target[, options])`
Seek to the key closest to `target`. Subsequent calls to `iterator.next()`, `nextv()` or `all()` (including implicit calls in a `for await...of` loop) will yield entries with keys equal to or larger than `target`, or equal to or smaller than `target` if the `reverse` option passed to `db.iterator()` was true.
The optional `options` object may contain:
- `keyEncoding`: custom key encoding, used to encode the `target`. By default the `keyEncoding` option of the iterator is used or (if that wasn't set) the `keyEncoding` of the database.
If range options like `gt` were passed to `db.iterator()` and `target` does not fall within that range, the iterator will reach its natural end.
#### `iterator.close([callback])`
Free up underlying resources. The `callback` function will be called with no arguments. If no callback is provided, a promise is returned. Closing the iterator is an idempotent operation, such that calling `close()` more than once is allowed and makes no difference.
If a `next()` ,`nextv()` or `all()` call is in progress, closing will wait for that to finish. After `close()` has been called, further calls to `next()` ,`nextv()` or `all()` will yield an error with code [`LEVEL_ITERATOR_NOT_OPEN`](https://github.com/Level/abstract-level#errors).
#### `iterator.db`
A reference to the database that created this iterator.
#### `iterator.count`
Read-only getter that indicates how many keys have been yielded so far (by any method) excluding calls that errored or yielded `undefined`.
#### `iterator.limit`
Read-only getter that reflects the `limit` that was set in options. Greater than or equal to zero. Equals `Infinity` if no limit, which allows for easy math:
```js
const hasMore = iterator.count < iterator.limit
const remaining = iterator.limit - iterator.count
```
### `keyIterator`
A key iterator has the same interface as `iterator` except that its methods yield keys instead of entries. For the `keyIterator.next(callback)` method, this means that the `callback` will receive two arguments (an error and key) instead of three. Usage is otherwise the same.
### `valueIterator`
A value iterator has the same interface as `iterator` except that its methods yield values instead of entries. For the `valueIterator.next(callback)` method, this means that the `callback` will receive two arguments (an error and value) instead of three. Usage is otherwise the same.
### `sublevel`
A sublevel is an instance of the `AbstractSublevel` class, which extends `AbstractLevel` and thus has the same API as documented above. Sublevels have a few additional properties.
#### `sublevel.prefix`
Prefix of the sublevel. A read-only string property.
```js
const example = db.sublevel('example')
const nested = example.sublevel('nested')
console.log(example.prefix) // '!example!'
console.log(nested.prefix) // '!example!!nested!'
```
#### `sublevel.db`
Parent database. A read-only property.
```js
const example = db.sublevel('example')
const nested = example.sublevel('nested')
console.log(example.db === db) // true
console.log(nested.db === db) // true
```
## Contributing
[`Level/level`](https://github.com/Level/level) is an **OPEN Open Source Project**. This means that:
> Individuals making significant and valuable contributions are given commit-access to the project to contribute as they see fit. This project is more like an open wiki than a standard guarded open source project.
See the [Contribution Guide](https://github.com/Level/community/blob/master/CONTRIBUTING.md) for more details.
## Donate
Support us with a monthly donation on [Open Collective](https://opencollective.com/level) and help us continue our work.
## License
[MIT](LICENSE)
[level-badge]: https://leveljs.org/img/badge.svg
+397
View File
@@ -0,0 +1,397 @@
# Upgrade Guide
This document describes breaking changes and how to upgrade. For a complete list of changes including minor and patch releases, please refer to the [changelog](CHANGELOG.md).
## 8.0.0
**This release replaces `leveldown` and `level-js` with [`classic-level`](https://github.com/Level/classic-level) and [`browser-level`](https://github.com/Level/browser-level). These modules implement the [`abstract-level`](https://github.com/Level/abstract-level) interface instead of [`abstract-leveldown`](https://github.com/Level/abstract-leveldown). This gives them the same API as `level@7` without having to be wrapped with [`levelup`](https://github.com/Level/levelup) or [`encoding-down`](https://github.com/Level/encoding-down). In addition, you can now choose to use Uint8Array instead of Buffer. Sublevels are built-in.**
We've put together several upgrade guides for different modules. See the [FAQ](https://github.com/Level/community#faq) to find the best upgrade guide for you. This one describes how to upgrade `level`.
Support of Node.js 10 has been dropped.
### Changes to initialization
We started using classes, which means using `new` is now required. If you previously did:
```js
const level = require('level')
const db = level('db')
```
You must now do:
```js
const { Level } = require('level')
const db = new Level('db')
```
### TypeScript makes a win
TypeScript type declarations are now included in the npm package(s). For `level` it's an intersection of `classic-level` and `browser-level` types that includes their options but excludes methods like `compactRange()` that can only be found in either. JavaScript folks using VSCode will also benefit from the new types because they enable auto-completion and now include documentation.
### Waking up from limbo
Deferred open - meaning that a database opens itself and any operations made in the mean time are queued up in memory - remains built-in. A new behavior is that those operations will yield errors if opening failed. They'd previously end up in limbo.
An `abstract-level` and thus `level` database is not "patch-safe". If some form of plugin monkey-patches a database method, it must now also take the responsibility of deferring the operation (as well as handling promises and callbacks) using [`db.defer()`](https://github.com/Level/abstract-level#dbdeferfn).
### Creating the location recursively
To align behavior between platforms, `classic-level` and therefore `level@8` creates the location directory recursively. While `leveldown` and therefore `level@7` would only do so on Windows. In the following example, the `foo` directory does not have to exist beforehand:
```js
const db = new Level('foo/bar')
```
This new behavior may break expectations, given typical filesystem behavior, or it could be a convenient feature, if the database is considered to abstract away the filesystem. We're [collecting feedback](https://github.com/Level/classic-level/issues/7) to determine what to do in a next (major) version. Your vote is most welcome!
### No constructor callback
The database constructor no longer takes a callback argument. Instead call `db.open()` if you wish to wait for opening (which is not necessary to use the database) or to capture an error. If that's your reason for using the callback and you previously initialized a database like so:
```js
level('fruits', function (err, db) {
// ..
})
```
You must now do one of:
```js
db.open(callback)
await db.open()
```
### There is only encodings
Encodings have a new home in `abstract-level` and are now powered by [`level-transcoder`](https://github.com/Level/transcoder). The main change is that logic from the existing public API has been expanded down into the storage layer. There are however a few differences from `level@7`. Some breaking:
- The lesser-used `'id'`, `'ascii'`, `'ucs2'` and `'utf16le'` encodings are not supported
- The undocumented `encoding` option (as an alias for `valueEncoding`) is not supported.
And some non-breaking:
- The `'binary'` encoding has been renamed to `'buffer'`, with `'binary'` as an alias
- The `'utf8'` encoding previously did not touch Buffers. Now it will call `buffer.toString('utf8')` for consistency. Consumers can use the `'buffer'` encoding to avoid this conversion.
Both `classic-level` and `browser-level` support Uint8Array data, in addition to Buffer. It's a separate encoding called `'view'` that can be used interchangeably:
```js
const db = new Level('people', { valueEncoding: 'view' })
await db.put('elena', new Uint8Array([97, 98, 99]))
await db.get('elena') // Uint8Array
await db.get('elena', { valueEncoding: 'utf8' }) // 'abc'
await db.get('elena', { valueEncoding: 'buffer' }) // Buffer
```
For browsers you can choose to use Uint8Array exclusively and omit the [`buffer`](https://github.com/feross/buffer) shim from your JavaScript bundle (through configuration of Webpack, Browserify or other).
### Streams have moved
Node.js readable streams must now be created with a new standalone module called [`level-read-stream`](https://github.com/Level/read-stream) rather than database methods like `db.createReadStream()`. For browsers you might prefer [`level-web-stream`](https://github.com/Level/web-stream) which does not require bundling the [`buffer`](https://github.com/feross/buffer) or [`readable-stream`](https://github.com/nodejs/readable-stream) shims. Both `level-read-stream` and `level-web-stream` can be used in Node.js and browsers. The former is significantly faster (also compared to `level@7`, thanks to a new `nextv()` method on iterators). The latter is a step towards a standard library for JavaScript across Node.js, Deno and browsers.
To offer an alternative to `db.createKeyStream()` and `db.createValueStream()`, two new types of iterators have been added: `db.keys()` and `db.values()`.
### State checks for safety
On any operation, an `abstract-level` and thus `level` database checks if it's open. If not, it will either throw an error (if the relevant API is synchronous) or asynchronously yield an error. For example:
```js
await db.close()
try {
db.iterator()
} catch (err) {
console.log(err.code) // LEVEL_DATABASE_NOT_OPEN
}
```
_Errors now have a `code` property. More on that below\._
### Zero-length keys and range options are now valid
These keys sort before anything else. Historically they weren't supported for causing segmentation faults in `leveldown`. That doesn't apply to today's codebase. You can now do:
```js
await db.put('', 'abc')
console.log(await db.get('')) // 'abc'
console.log(await db.get(new Uint8Array(0), { keyEncoding: 'view' })) // 'abc'
for await (const [key, value] of db.iterator({ lte: '' })) {
console.log(value) // 'abc'
}
```
### It doesn't end there
The `iterator.end()` method has been renamed to `iterator.close()`, with `end()` being an alias until a next major version. The term "close" makes it easier to differentiate between the iterator having reached its natural end (data-wise) versus closing it to cleanup resources. If you previously did:
```js
const iterator = db.iterator()
iterator.end(callback)
```
You should now do one of:
```js
iterator.close(callback)
await iterator.close()
```
On `db.close()`, non-closed iterators are now automatically closed (only for safety reasons). If a call like `next()` is in progress, closing the iterator or database will wait for that. Calling `iterator.close()` more than once is now allowed and makes no difference.
### Other changes to iterators
- In browsers, backpressure is now preferred over snapshot guarantees. For details, please see [`browser-level@1`](https://github.com/Level/browser-level/blob/main/UPGRADING.md#100). On the flip side, `iterator.seek()` now also works in browsers.
- Use of [`level-concat-iterator`](https://github.com/Level/concat-iterator) can be replaced with [`iterator.all()`](https://github.com/Level/level#iteratoralloptions-callback). The former does support `abstract-level` databases but the latter is optimized and always has snapshot guarantees.
- The previously undocumented `highWaterMark` option of `leveldown` is called [`highWaterMarkBytes`](https://github.com/Level/classic-level#about-high-water) in `classic-level` to remove a conflict with streams.
- On iterators with `{ keys: false }` or `{ values: false }` options, the yielded key or value is now consistently `undefined`.
### A chained batch should be closed
Chained batch has a new method `close()` which is an idempotent operation and automatically called after `write()` (for backwards compatibility) or on `db.close()`. This to ensure batches can't be used after closing and reopening a db. If a `write()` is in progress, closing will wait for that. If `write()` is never called then `close()` must be and that's a breaking change because inaction will cause memory leaks. For example:
```js
const batch = db.batch()
.put('elena', 'abc')
.del('steve')
if (someCondition) {
await batch.write()
} else {
// Decided not to commit
await batch.close()
}
// In either case this will throw
batch.put('daniel', 'xyz')
```
### Errors now use codes
The [`level-errors`](https://github.com/Level/errors) module is no longer used or exposed by `level@8`. Instead errors thrown or yielded from a database [have a `code` property](https://github.com/Level/abstract-level#errors). Going forward, the semver contract will be on `code` and error messages will change without a semver-major bump.
To minimize breakage, the most used error as yielded by `get()` when an entry is not found, has the same properties that `level-errors` added (`notFound` and `status`) in addition to code `LEVEL_NOT_FOUND`. Those properties will be removed in a future version. If you previously did:
```js
db.get('abc', function (err, value) {
if (err && err.notFound) {
// Handle missing entry
}
})
```
That will still work but it's preferred to do:
```js
db.get('abc', function (err, value) {
if (err && err.code === 'LEVEL_NOT_FOUND') {
// Handle missing entry
}
})
```
Or using promises:
```js
try {
const value = await db.get('abc')
} catch (err) {
if (err.code === 'LEVEL_NOT_FOUND') {
// Handle missing entry
}
}
```
Side note: it's been suggested more than once to remove this error altogether and we likely will after the dust has settled on `abstract-level`.
### Changes to lesser-used properties and methods
The following properties and methods can no longer be accessed, as they've been removed, renamed or replaced with internal [symbols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol).
| Object | Property or method | Original module | New module |
| :------------ | :------------------------ | :------------------- | :--------------- |
| db | `_setupIteratorOptions()` | `abstract-leveldown` | `abstract-level` |
| db | `prefix` <sup>1</sup> | `level-js` | `browser-level` |
| db | `upgrade()` | `level-js` | `browser-level` |
| iterator | `_nexting` | `abstract-leveldown` | `abstract-level` |
| iterator | `_ended` | `abstract-leveldown` | `abstract-level` |
| iterator | `cache` <sup>2</sup> | `leveldown` | `classic-level` |
| iterator | `finished` | `leveldown` | `classic-level` |
| chained batch | `_written` | `abstract-leveldown` | `abstract-level` |
| chained batch | `_checkWritten()` | `abstract-leveldown` | `abstract-level` |
| chained batch | `_operations` | `abstract-leveldown` | `abstract-level` |
<small>
1. Conflicted with the `db.prefix` property of sublevels. Renamed to `db.namePrefix`.
2. If you were using this then you'll want to checkout the new [`nextv()`](https://github.com/Level/level#iteratornextvsize-options-callback) method.
</small>
The following properties are now read-only getters.
| Object | Property | Original module | New module |
| :------------ | :----------------- | :------------------- | :--------------- |
| db | `status` | `abstract-leveldown` | `abstract-level` |
| db | `location` | `leveldown` | `classic-level` |
| db | `location` | `level-js` | `browser-level` |
| db | `namePrefix` | `level-js` | `browser-level` |
| db | `version` | `level-js` | `browser-level` |
| db | `db` (IDBDatabase) | `level-js` | `browser-level` |
| chained batch | `length` | `levelup` | `abstract-level` |
### Sublevels are built-in
_This section is only relevant if you use [`subleveldown`](https://github.com/Level/subleveldown), which can not wrap a `level@8` database._
If you previously did:
```js
const sub = require('subleveldown')
const example1 = sub(db, 'example1')
const example2 = sub(db, 'example2', { valueEncoding: 'json' })
```
You must now do:
```js
const example1 = db.sublevel('example1')
const example2 = db.sublevel('example2', { valueEncoding: 'json' })
```
The key structure is equal to that of `subleveldown`. This means that a sublevel can read sublevels previously created with (and populated by) `subleveldown`. There are some new features:
- `db.batch(..)` takes a `sublevel` option on operations, to atomically commit data to multiple sublevels
- Sublevels support Uint8Array in addition to Buffer.
To reduce function overloads, the prefix argument (`example1` above) is now required and it's called `name` here. If you previously did one of the following, resulting in an empty name:
```js
subleveldown(db)
subleveldown(db, { separator: '@' })
```
You must now use an explicit empty name:
```js
db.sublevel('')
db.sublevel('', { separator: '@' })
```
The string shorthand for `{ separator }` has also been removed. If you previously did:
```js
subleveldown(db, 'example', '@')
```
You must now do:
```js
db.sublevel('example', { separator: '@' })
```
Third, the `open` option has been removed. If you need an asynchronous open hook, feel free to open an issue to discuss restoring this API.
Lastly, the error message `Parent database is not open` (courtesy of `subleveldown` which had to check open state to prevent segmentation faults from underlying databases) changed to error code [`LEVEL_DATABASE_NOT_OPEN`](https://github.com/Level/abstract-level#errors) (courtesy of `abstract-level` which does those checks on any database).
## 7.0.0
Legacy range options have been removed ([Level/community#86](https://github.com/Level/community/issues/86)). If you previously did:
```js
db.createReadStream({ start: 'a', end: 'z' })
```
An error would now be thrown and you must instead do:
```js
db.createReadStream({ gte: 'a', lte: 'z' })
```
The same applies to `db.iterator()`, `db.createKeyStream()` and `db.createValueStream()`.
This release also drops support of legacy runtime environments ([Level/community#98](https://github.com/Level/community/issues/98)):
- Node.js 6 and 8
- Internet Explorer 11
- Safari 9-11
- Stock Android browser (AOSP).
Lastly, in browsers, the [`immediate`](https://github.com/calvinmetcalf/immediate) and `process` browser shims for `process.nextTick()` have been replaced with the smaller [`queue-microtask`](https://github.com/feross/queue-microtask), except in streams. In the future we might use `queueMicrotask()` in Node.js too.
## 6.0.0
**No breaking changes to the `level` API. If you're only using `level` in Node.js or Electron, you can upgrade without thinking twice.**
The major bump is for browsers, because `level` upgraded to [`level-js@5`](https://github.com/Level/level-js):
> Support of keys & values other than strings and Buffers has been dropped. Internally `level-js` now stores keys & values as binary which solves a number of compatibility issues ([Level/memdown#186](https://github.com/Level/memdown/issues/186)). If you pass in a key or value that isn't a string or Buffer, it will be irreversibly stringified.
>
> Existing IndexedDB databases created with `level-js@4` \[via `level@5`] can be read only if they used binary keys and string or binary values. Other types will come out stringified, and string keys will sort incorrectly. Use the included `upgrade()` utility to convert stored data to binary (in so far the environment supports it):
>
> ```js
> var level = require('level')
> var reachdown = require('reachdown')
> var db = level('my-db')
>
> db.open(function (err) {
> if (err) throw err
>
> reachdown(db, 'level-js').upgrade(function (err) {
> if (err) throw err
> })
> })
> ```
### New Features :sparkles:
In case you missed it (a few of these already floated into `level@5`) some exciting new features are now available in all environments:
- Added [`db.clear()`](https://github.com/Level/level#dbclearoptions-callback) to delete all entries or a range! Also works in [`subleveldown`](https://github.com/Level/subleveldown) - empty that bucket!
- Check out [`db.supports`](https://github.com/Level/level#supports): a manifest describing the features of a db!
- Glorious: `leveldown` ships a prebuilt binary for Linux that is now [compatible with Debian 8, Ubuntu 14.04, RHEL 7, CentOS 7 and other flavors with an old glibc](https://github.com/Level/leveldown/pull/674)!
- With thanks to [Cirrus CI](https://cirrus-ci.org/), `leveldown` is now [continuously tested in FreeBSD](https://github.com/Level/leveldown/pull/678)!
Go forth and build amazing things.
## 5.0.0
Upgraded to [`leveldown@5.0.0`](https://github.com/Level/leveldown/blob/v5.0.0/UPGRADING.md#v5) and (through `level-packager@5`) [`levelup@4`](https://github.com/Level/levelup/blob/v4.0.0/UPGRADING.md#v4) and [`encoding-down@6`](https://github.com/Level/encoding-down/blob/v6.0.0/UPGRADING.md#v6). Please follow these links for more information. A quick summary: range options (e.g. `gt`) are now serialized the same as keys, `{ gt: undefined }` is not the same as `{}`, nullish values are now rejected and streams are backed by [`readable-stream@3`](https://github.com/nodejs/readable-stream#version-3xx).
In addition, `level` got browser support! It uses [`leveldown`](https://github.com/Level/leveldown) in node and [`level-js`](https://github.com/Level/level-js) in browsers (backed by [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API)). As such, [`level-browserify`](https://github.com/Level/level-browserify) is not needed anymore and will be deprecated later on. To learn what the integration of `level-js` means for platform, browser and type support, please see the updated [README](README.md#supported-platforms).
## 4.0.0
Dropped support for node 4. No other breaking changes.
## 3.0.0
No breaking changes to the `level` API.
This is an upgrade to `leveldown@^3.0.0` which is based on `abstract-leveldown@~4.0.0` which in turn contains breaking changes to [`.batch()`](https://github.com/Level/abstract-leveldown/commit/a2621ad70571f6ade9d2be42632ece042e068805). Though this is negated by `levelup`, we decided to release a new major version in the event of dependents reaching down into `db.db`.
## 2.0.0
No breaking changes to the `level` API.
The parts that make up `level` have been refactored to increase modularity. This is an upgrade to `leveldown@~2.0.0` and `level-packager@~2.0.0`, which in turn upgraded to `levelup@^2.0.0`. The responsibility of encoding keys and values moved from [`levelup`](https://github.com/Level/levelup) to [`encoding-down`](https://github.com/Level/encoding-down), which comes bundled with [`level-packager`](https://github.com/Level/packager).
Being a convenience package, `level` glues the parts back together to form a drop-in replacement for the users of `levelup@1`, while staying fully compatible with `level@1`. One thing we do get for free, is native Promise support.
```js
const db = level('db')
await db.put('foo', 'bar')
console.log(await db.get('foo'))
```
This does not affect the existing callback API, functionality-wise or performance-wise.
For more information please check the corresponding `CHANGELOG.md` for:
- [`levelup`](https://github.com/Level/levelup/blob/master/CHANGELOG.md)
- [`leveldown`](https://github.com/Level/leveldown/blob/master/CHANGELOG.md)
- [`level-packager`](https://github.com/Level/packager/blob/master/CHANGELOG.md)
+1
View File
@@ -0,0 +1 @@
exports.Level = require('browser-level').BrowserLevel
+87
View File
@@ -0,0 +1,87 @@
import * as AbstractLevel from 'abstract-level'
import * as ClassicLevel from 'classic-level'
import * as BrowserLevel from 'browser-level'
/**
* Universal {@link AbstractLevel} database for Node.js and browsers.
*
* @template KDefault The default type of keys if not overridden on operations.
* @template VDefault The default type of values if not overridden on operations.
*/
export class Level<KDefault = string, VDefault = string>
extends AbstractLevel.AbstractLevel<string | Buffer | Uint8Array, KDefault, VDefault> {
/**
* Database constructor.
*
* @param location Directory path (relative or absolute) where LevelDB will store its
* files, or in browsers, the name of the
* [`IDBDatabase`](https://developer.mozilla.org/en-US/docs/Web/API/IDBDatabase) to be
* opened.
* @param options Options, of which some will be forwarded to {@link open}.
*/
constructor (location: string, options?: DatabaseOptions<KDefault, VDefault> | undefined)
/**
* Location that was passed to the constructor.
*/
get location (): string
open (): Promise<void>
open (options: OpenOptions): Promise<void>
open (callback: AbstractLevel.NodeCallback<void>): void
open (options: OpenOptions, callback: AbstractLevel.NodeCallback<void>): void
get (key: KDefault): Promise<VDefault>
get (key: KDefault, callback: AbstractLevel.NodeCallback<VDefault>): void
get<K = KDefault, V = VDefault> (key: K, options: GetOptions<K, V>): Promise<V>
get<K = KDefault, V = VDefault> (key: K, options: GetOptions<K, V>, callback: AbstractLevel.NodeCallback<V>): void
getMany (keys: KDefault[]): Promise<VDefault[]>
getMany (keys: KDefault[], callback: AbstractLevel.NodeCallback<VDefault[]>): void
getMany<K = KDefault, V = VDefault> (keys: K[], options: GetManyOptions<K, V>): Promise<V[]>
getMany<K = KDefault, V = VDefault> (keys: K[], options: GetManyOptions<K, V>, callback: AbstractLevel.NodeCallback<V[]>): void
put (key: KDefault, value: VDefault): Promise<void>
put (key: KDefault, value: VDefault, callback: AbstractLevel.NodeCallback<void>): void
put<K = KDefault, V = VDefault> (key: K, value: V, options: PutOptions<K, V>): Promise<void>
put<K = KDefault, V = VDefault> (key: K, value: V, options: PutOptions<K, V>, callback: AbstractLevel.NodeCallback<void>): void
del (key: KDefault): Promise<void>
del (key: KDefault, callback: AbstractLevel.NodeCallback<void>): void
del<K = KDefault> (key: K, options: DelOptions<K>): Promise<void>
del<K = KDefault> (key: K, options: DelOptions<K>, callback: AbstractLevel.NodeCallback<void>): void
batch (operations: Array<BatchOperation<typeof this, KDefault, VDefault>>): Promise<void>
batch (operations: Array<BatchOperation<typeof this, KDefault, VDefault>>, callback: AbstractLevel.NodeCallback<void>): void
batch<K = KDefault, V = VDefault> (operations: Array<BatchOperation<typeof this, K, V>>, options: BatchOptions<K, V>): Promise<void>
batch<K = KDefault, V = VDefault> (operations: Array<BatchOperation<typeof this, K, V>>, options: BatchOptions<K, V>, callback: AbstractLevel.NodeCallback<void>): void
batch (): ChainedBatch<typeof this, KDefault, VDefault>
iterator (): Iterator<typeof this, KDefault, VDefault>
iterator<K = KDefault, V = VDefault> (options: IteratorOptions<K, V>): Iterator<typeof this, K, V>
keys (): KeyIterator<typeof this, KDefault>
keys<K = KDefault> (options: KeyIteratorOptions<K>): KeyIterator<typeof this, K>
values (): ValueIterator<typeof this, KDefault, VDefault>
values<K = KDefault, V = VDefault> (options: ValueIteratorOptions<K, V>): ValueIterator<typeof this, K, V>
}
export type DatabaseOptions<K, V> = ClassicLevel.DatabaseOptions<K, V> & BrowserLevel.DatabaseOptions<K, V>
export type OpenOptions = ClassicLevel.OpenOptions & BrowserLevel.OpenOptions
export type GetOptions<K, V> = ClassicLevel.GetOptions<K, V> & BrowserLevel.GetOptions<K, V>
export type GetManyOptions<K, V> = ClassicLevel.GetManyOptions<K, V> & BrowserLevel.GetManyOptions<K, V>
export type PutOptions<K, V> = ClassicLevel.PutOptions<K, V> & BrowserLevel.PutOptions<K, V>
export type DelOptions<K> = ClassicLevel.DelOptions<K> & BrowserLevel.DelOptions<K>
export type BatchOptions<K, V> = ClassicLevel.BatchOptions<K, V> & BrowserLevel.BatchOptions<K, V>
export type BatchOperation<TDatabase, K, V> = ClassicLevel.BatchOperation<TDatabase, K, V> & BrowserLevel.BatchOperation<TDatabase, K, V>
export type ChainedBatch<TDatabase, K, V> = ClassicLevel.ChainedBatch<TDatabase, K, V> & BrowserLevel.ChainedBatch<TDatabase, K, V>
export type Iterator<TDatabase, K, V> = ClassicLevel.Iterator<TDatabase, K, V> & BrowserLevel.Iterator<TDatabase, K, V>
export type KeyIterator<TDatabase, K> = ClassicLevel.KeyIterator<TDatabase, K> & BrowserLevel.KeyIterator<TDatabase, K>
export type ValueIterator<TDatabase, K, V> = ClassicLevel.ValueIterator<TDatabase, K, V> & BrowserLevel.ValueIterator<TDatabase, K, V>
export type IteratorOptions<K, V> = ClassicLevel.IteratorOptions<K, V> & BrowserLevel.IteratorOptions<K, V>
export type KeyIteratorOptions<K> = ClassicLevel.KeyIteratorOptions<K> & BrowserLevel.KeyIteratorOptions<K>
export type ValueIteratorOptions<K, V> = ClassicLevel.ValueIteratorOptions<K, V> & BrowserLevel.ValueIteratorOptions<K, V>
+1
View File
@@ -0,0 +1 @@
exports.Level = require('classic-level').ClassicLevel
+61
View File
@@ -0,0 +1,61 @@
{
"name": "level",
"version": "8.0.1",
"description": "Universal abstract-level database for Node.js and browsers",
"license": "MIT",
"main": "index.js",
"types": "./index.d.ts",
"scripts": {
"test": "standard && ts-standard *.ts && nyc node test.js",
"test-browsers-local": "airtap --coverage test.js && nyc report",
"coverage": "nyc report -r lcovonly"
},
"files": [
"browser.js",
"index.js",
"index.d.ts",
"CHANGELOG.md",
"UPGRADING.md"
],
"browser": "browser.js",
"dependencies": {
"abstract-level": "^1.0.4",
"browser-level": "^1.0.1",
"classic-level": "^1.2.0"
},
"devDependencies": {
"@types/node": "^18.0.0",
"@voxpelli/tsconfig": "^4.0.0",
"airtap": "^4.0.1",
"airtap-playwright": "^1.0.1",
"hallmark": "^4.0.0",
"nyc": "^15.0.0",
"standard": "^16.0.3",
"tape": "^5.0.1",
"ts-standard": "^11.0.0",
"typescript": "^4.5.5",
"uuid": "^9.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/level"
},
"repository": {
"type": "git",
"url": "https://github.com/Level/level.git"
},
"homepage": "https://github.com/Level/level",
"keywords": [
"level",
"leveldb",
"stream",
"database",
"db",
"store",
"storage",
"json"
],
"engines": {
"node": ">=12"
}
}
+117
View File
@@ -0,0 +1,117 @@
{
"name": "@web5/dids",
"version": "1.1.0",
"description": "TBD DIDs library",
"type": "module",
"main": "./dist/cjs/index.js",
"module": "./dist/esm/index.js",
"types": "./dist/types/index.d.ts",
"homepage": "https://github.com/TBD54566975/web5-js/tree/main/packages/dids#readme",
"bugs": "https://github.com/TBD54566975/web5-js/issues",
"repository": {
"type": "git",
"url": "git+https://github.com/TBD54566975/web5-js.git",
"directory": "packages/dids"
},
"license": "Apache-2.0",
"contributors": [
{
"name": "Daniel Buchner",
"url": "https://github.com/csuwildcat"
},
{
"name": "Frank Hinek",
"url": "https://github.com/frankhinek"
},
{
"name": "Moe Jangda",
"url": "https://github.com/mistermoe"
}
],
"files": [
"dist",
"src"
],
"exports": {
".": {
"types": "./dist/types/index.d.ts",
"import": "./dist/esm/index.js",
"require": "./dist/cjs/index.js"
},
"./utils": {
"types": "./dist/types/utils.d.ts",
"import": "./dist/esm/utils.js",
"require": "./dist/cjs/utils.js"
}
},
"react-native": "./dist/esm/index.js",
"keywords": [
"decentralized",
"decentralized-identity",
"DID",
"did:ion",
"did:key",
"did-utils",
"self-sovereign-identity",
"web5"
],
"publishConfig": {
"access": "public",
"provenance": true
},
"engines": {
"node": ">=18.0.0"
},
"dependencies": {
"@decentralized-identity/ion-sdk": "1.0.4",
"@dnsquery/dns-packet": "6.1.1",
"@web5/common": "1.0.0",
"@web5/crypto": "1.0.0",
"abstract-level": "1.0.4",
"bencode": "4.0.0",
"buffer": "6.0.3",
"level": "8.0.1",
"ms": "2.1.3"
},
"devDependencies": {
"@playwright/test": "1.40.1",
"@types/bencode": "2.0.4",
"@types/chai": "4.3.16",
"@types/chai-as-promised": "7.1.8",
"@types/eslint": "8.56.10",
"@types/mocha": "10.0.6",
"@types/ms": "0.7.34",
"@types/node": "20.12.12",
"@types/sinon": "17.0.2",
"@typescript-eslint/eslint-plugin": "7.9.0",
"@typescript-eslint/parser": "7.10.0",
"@web/test-runner": "0.18.0",
"@web/test-runner-playwright": "0.11.0",
"c8": "9.1.0",
"chai": "5.1.1",
"chai-as-promised": "7.1.2",
"esbuild": "0.19.8",
"eslint": "9.3.0",
"eslint-plugin-mocha": "10.4.3",
"mocha": "10.4.0",
"mocha-junit-reporter": "2.2.1",
"playwright": "1.44.0",
"rimraf": "5.0.7",
"sinon": "18.0.0",
"source-map-loader": "5.0.0",
"typescript": "5.4.5"
},
"scripts": {
"clean": "rimraf dist coverage tests/compiled",
"build:esm": "rimraf dist/esm dist/types && pnpm tsc -p tsconfig.json",
"build:cjs": "rimraf dist/cjs && node build/cjs-bundle.js && echo '{\"type\": \"commonjs\"}' > ./dist/cjs/package.json",
"build:browser": "rimraf dist/browser.mjs dist/browser.js && node build/bundles.js",
"build:tests:node": "rimraf tests/compiled && pnpm tsc -p tests/tsconfig.json",
"build:tests:browser": "rimraf tests/compiled && node build/esbuild-tests.cjs",
"build": "pnpm clean && pnpm build:esm && pnpm build:cjs && pnpm build:browser",
"lint": "eslint . --max-warnings 0",
"lint:fix": "eslint . --fix",
"test:node": "pnpm build:tests:node && pnpm c8 mocha",
"test:browser": "pnpm build:tests:browser && web-test-runner"
}
}
+280
View File
@@ -0,0 +1,280 @@
import type {
Jwk,
Signer,
CryptoApi,
KeyIdentifier,
EnclosedSignParams,
KmsExportKeyParams,
KmsImportKeyParams,
KeyImporterExporter,
EnclosedVerifyParams,
} from '@web5/crypto';
import { LocalKeyManager, utils as cryptoUtils } from '@web5/crypto';
import type { DidDocument } from './types/did-core.js';
import type { DidMetadata, PortableDid } from './types/portable-did.js';
import { DidError, DidErrorCode } from './did-error.js';
import { extractDidFragment, getVerificationMethods } from './utils.js';
/**
* A `BearerDidSigner` extends the {@link Signer} interface to include specific properties for
* signing with a Decentralized Identifier (DID). It encapsulates the algorithm and key identifier,
* which are often needed when signing JWTs, JWSs, JWEs, and other data structures.
*
* Typically, the algorithm and key identifier are used to populate the `alg` and `kid` fields of a
* JWT or JWS header.
*/
export interface BearerDidSigner extends Signer {
/**
* The cryptographic algorithm identifier used for signing operations.
*
* Typically, this value is used to populate the `alg` field of a JWT or JWS header. The
* registered algorithm names are defined in the
* {@link https://www.iana.org/assignments/jose/jose.xhtml#web-signature-encryption-algorithms | IANA JSON Web Signature and Encryption Algorithms registry}.
*
* @example
* "ES256" // ECDSA using P-256 and SHA-256
*/
algorithm: string;
/**
* The unique identifier of the key within the DID document that is used for signing and
* verification operations.
*
* This identifier must be a DID URI with a fragment (e.g., did:method:123#key-0) that references
* a specific verification method in the DID document. It allows users of a `BearerDidSigner` to
* determine the DID and key that will be used for signing and verification operations.
*
* @example
* "did:dht:123#key-1" // A fragment identifier referring to a key in the DID document
*/
keyId: string;
}
/**
* Represents a Decentralized Identifier (DID) along with its DID document, key manager, metadata,
* and convenience functions.
*/
export class BearerDid {
/** {@inheritDoc Did#uri} */
uri: string;
/**
* The DID document associated with this DID.
*
* @see {@link https://www.w3.org/TR/did-core/#dfn-diddocument | DID Core Specification, § DID Document}
*/
document: DidDocument;
/** {@inheritDoc DidMetadata} */
metadata: DidMetadata;
/**
* Key Management System (KMS) used to manage the DIDs keys and sign data.
*
* Each DID method requires at least one key be present in the provided `keyManager`.
*/
keyManager: CryptoApi;
constructor({ uri, document, metadata, keyManager }: {
uri: string,
document: DidDocument,
metadata: DidMetadata,
keyManager: CryptoApi
}) {
this.uri = uri;
this.document = document;
this.metadata = metadata;
this.keyManager = keyManager;
}
/**
* Converts a `BearerDid` object to a portable format containing the URI and verification methods
* associated with the DID.
*
* This method is useful when you need to represent the key material and metadata associated with
* a DID in format that can be used independently of the specific DID method implementation. It
* extracts both public and private keys from the DID's key manager and organizes them into a
* `PortableDid` structure.
*
* @remarks
* If the DID's key manager does not allow private keys to be exported, the `PortableDid` returned
* will not contain a `privateKeys` property. This enables the importing and exporting DIDs that
* use the same underlying KMS even if the KMS does not support exporting private keys. Examples
* include hardware security modules (HSMs) and cloud-based KMS services like AWS KMS.
*
* If the DID's key manager does support exporting private keys, the resulting `PortableDid` will
* include a `privateKeys` property which contains the same number of entries as there are
* verification methods as the DID document, each with its associated private key and the
* purpose(s) for which the key can be used (e.g., `authentication`, `assertionMethod`, etc.).
*
* @example
* ```ts
* // Assuming `did` is an instance of BearerDid
* const portableDid = await did.export();
* // portableDid now contains the DID URI, document, metadata, and optionally, private keys.
* ```
*
* @returns A `PortableDid` containing the URI, DID document, metadata, and optionally private
* keys associated with the `BearerDid`.
* @throws An error if the DID document does not contain any verification methods or the keys for
* any verification method are missing in the key manager.
*/
public async export(): Promise<PortableDid> {
// Verify the DID document contains at least one verification method.
if (!(Array.isArray(this.document.verificationMethod) && this.document.verificationMethod.length > 0)) {
throw new Error(`DID document for '${this.uri}' is missing verification methods`);
}
// Create a new `PortableDid` object to store the exported data.
let portableDid: PortableDid = {
uri : this.uri,
document : this.document,
metadata : this.metadata
};
// If the BearerDid's key manager supports exporting private keys, add them to the portable DID.
if ('exportKey' in this.keyManager && typeof this.keyManager.exportKey === 'function') {
const privateKeys: Jwk[] = [];
for (let vm of this.document.verificationMethod) {
if (!vm.publicKeyJwk) {
throw new Error(`Verification method '${vm.id}' does not contain a public key in JWK format`);
}
// Compute the key URI of the verification method's public key.
const keyUri = await this.keyManager.getKeyUri({ key: vm.publicKeyJwk });
// Retrieve the private key from the key manager.
const privateKey = await this.keyManager.exportKey({ keyUri }) as Jwk;
// Add the verification method to the key set.
privateKeys.push({ ...privateKey });
}
portableDid.privateKeys = privateKeys;
}
return portableDid;
}
/**
* Return a {@link Signer} that can be used to sign messages, credentials, or arbitrary data.
*
* If given, the `methodId` parameter is used to select a key from the verification methods
* present in the DID Document.
*
* If `methodID` is not given, the first verification method intended for signing claims is used.
*
* @param params - The parameters for the `getSigner` operation.
* @param params.methodId - ID of the verification method key that will be used for sign and
* verify operations. Optional.
* @returns An instantiated {@link Signer} that can be used to sign and verify data.
*/
public async getSigner(params?: { methodId: string }): Promise<BearerDidSigner> {
// Attempt to find a verification method that matches the given method ID, or if not given,
// find the first verification method intended for signing claims.
const verificationMethod = this.document.verificationMethod?.find(
vm => extractDidFragment(vm.id) === (extractDidFragment(params?.methodId) ?? extractDidFragment(this.document.assertionMethod?.[0]))
);
if (!(verificationMethod && verificationMethod.publicKeyJwk)) {
throw new DidError(DidErrorCode.InternalError, 'A verification method intended for signing could not be determined from the DID Document');
}
// Compute the expected key URI of the signing key.
const keyUri = await this.keyManager.getKeyUri({ key: verificationMethod.publicKeyJwk });
// Get the public key to be used for verify operations, which also verifies that the key is
// present in the key manager's store.
const publicKey = await this.keyManager.getPublicKey({ keyUri });
// Bind the DID's key manager to the signer.
const keyManager = this.keyManager;
// Determine the signing algorithm.
const algorithm = cryptoUtils.getJoseSignatureAlgorithmFromPublicKey(publicKey);
return {
algorithm : algorithm,
keyId : verificationMethod.id,
async sign({ data }: EnclosedSignParams): Promise<Uint8Array> {
const signature = await keyManager.sign({ data, keyUri: keyUri! }); // `keyUri` is guaranteed to be defined at this point.
return signature;
},
async verify({ data, signature }: EnclosedVerifyParams): Promise<boolean> {
const isValid = await keyManager.verify({ data, key: publicKey!, signature }); // `publicKey` is guaranteed to be defined at this point.
return isValid;
}
};
}
/**
* Instantiates a {@link BearerDid} object from a given {@link PortableDid}.
*
* This method allows for the creation of a `BearerDid` object using a previously created DID's
* key material, DID document, and metadata.
*
* @example
* ```ts
* // Export an existing BearerDid to PortableDid format.
* const portableDid = await did.export();
* // Reconstruct a BearerDid object from the PortableDid.
* const did = await BearerDid.import({ portableDid });
* ```
*
* @param params - The parameters for the import operation.
* @param params.portableDid - The PortableDid object to import.
* @param params.keyManager - Optionally specify an external Key Management System (KMS) used to
* generate keys and sign data. If not given, a new
* {@link LocalKeyManager} instance will be created and
* used.
* @returns A Promise resolving to a `BearerDid` object representing the DID formed from the
* provided PortableDid.
* @throws An error if the PortableDid document does not contain any verification methods or the
* keys for any verification method are missing in the key manager.
*/
public static async import({ portableDid, keyManager = new LocalKeyManager() }: {
keyManager?: CryptoApi & KeyImporterExporter<KmsImportKeyParams, KeyIdentifier, KmsExportKeyParams>;
portableDid: PortableDid;
}): Promise<BearerDid> {
// Get all verification methods from the given DID document, including embedded methods.
const verificationMethods = getVerificationMethods({ didDocument: portableDid.document });
// Validate that the DID document contains at least one verification method.
if (verificationMethods.length === 0) {
throw new DidError(DidErrorCode.InvalidDidDocument, `At least one verification method is required but 0 were given`);
}
// If given, import the private key material into the key manager.
for (let key of portableDid.privateKeys ?? []) {
await keyManager.importKey({ key });
}
// Validate that the key material for every verification method in the DID document is present
// in the key manager.
for (let vm of verificationMethods) {
if (!vm.publicKeyJwk) {
throw new Error(`Verification method '${vm.id}' does not contain a public key in JWK format`);
}
// Compute the key URI of the verification method's public key.
const keyUri = await keyManager.getKeyUri({ key: vm.publicKeyJwk });
// Verify that the key is present in the key manager. If not, an error is thrown.
await keyManager.getPublicKey({ keyUri });
}
// Use the given PortableDid to construct the BearerDid object.
const did = new BearerDid({
uri : portableDid.uri,
document : portableDid.document,
metadata : portableDid.metadata,
keyManager
});
return did;
}
}
+75
View File
@@ -0,0 +1,75 @@
/**
* A custom error class for DID-related errors.
*/
export class DidError extends Error {
/**
* Constructs an instance of DidError, a custom error class for handling DID-related errors.
*
* @param code - A {@link DidErrorCode} representing the specific type of error encountered.
* @param message - A human-readable description of the error.
*/
constructor(public code: DidErrorCode, message: string) {
super(`${code}: ${message}`);
this.name = 'DidError';
// Ensures that instanceof works properly, the correct prototype chain when using inheritance,
// and that V8 stack traces (like Chrome, Edge, and Node.js) are more readable and relevant.
Object.setPrototypeOf(this, new.target.prototype);
// Captures the stack trace in V8 engines (like Chrome, Edge, and Node.js).
// In non-V8 environments, the stack trace will still be captured.
if (Error.captureStackTrace) {
Error.captureStackTrace(this, DidError);
}
}
}
/**
* An enumeration of possible DID error codes.
*/
export enum DidErrorCode {
/** The DID supplied does not conform to valid syntax. */
InvalidDid = 'invalidDid',
/** The supplied method name is not supported by the DID method and/or DID resolver implementation. */
MethodNotSupported = 'methodNotSupported',
/** An unexpected error occurred during the requested DID operation. */
InternalError = 'internalError',
/** The DID document supplied does not conform to valid syntax. */
InvalidDidDocument = 'invalidDidDocument',
/** The byte length of a DID document does not match the expected value. */
InvalidDidDocumentLength = 'invalidDidDocumentLength',
/** The DID URL supplied to the dereferencing function does not conform to valid syntax. */
InvalidDidUrl = 'invalidDidUrl',
/** The given proof of a previous DID is invalid */
InvalidPreviousDidProof = 'invalidPreviousDidProof',
/** An invalid public key is detected during a DID operation. */
InvalidPublicKey = 'invalidPublicKey',
/** The byte length of a public key does not match the expected value. */
InvalidPublicKeyLength = 'invalidPublicKeyLength',
/** An invalid public key type was detected during a DID operation. */
InvalidPublicKeyType = 'invalidPublicKeyType',
/** Verification of a signature failed during a DID operation. */
InvalidSignature = 'invalidSignature',
/** The DID resolver was unable to find the DID document resulting from the resolution request. */
NotFound = 'notFound',
/**
* The representation requested via the `accept` input metadata property is not supported by the
* DID method and/or DID resolver implementation.
*/
RepresentationNotSupported = 'representationNotSupported',
/** The type of a public key is not supported by the DID method and/or DID resolver implementation. */
UnsupportedPublicKeyType = 'unsupportedPublicKeyType',
}
+186
View File
@@ -0,0 +1,186 @@
/**
* The `Did` class represents a Decentralized Identifier (DID) Uniform Resource Identifier (URI).
*
* This class provides a method for parsing a DID URI string into its component parts, as well as a
* method for serializing a DID URI object into a string.
*
* A DID URI is composed of the following components:
* - scheme
* - method
* - id
* - path
* - query
* - fragment
* - params
*
* @see {@link https://www.w3.org/TR/did-core/#did-syntax | DID Core Specification, § DID Syntax}
*/
export class Did {
/** Regular expression pattern for matching the method component of a DID URI. */
static readonly METHOD_PATTERN = '([a-z0-9]+)';
/** Regular expression pattern for matching percent-encoded characters in a method identifier. */
static readonly PCT_ENCODED_PATTERN = '(?:%[0-9a-fA-F]{2})';
/** Regular expression pattern for matching the characters allowed in a method identifier. */
static readonly ID_CHAR_PATTERN = `(?:[a-zA-Z0-9._-]|${Did.PCT_ENCODED_PATTERN})`;
/** Regular expression pattern for matching the method identifier component of a DID URI. */
static readonly METHOD_ID_PATTERN = `((?:${Did.ID_CHAR_PATTERN}*:)*(${Did.ID_CHAR_PATTERN}+))`;
/** Regular expression pattern for matching the path component of a DID URI. */
static readonly PATH_PATTERN = `(/[^#?]*)?`;
/** Regular expression pattern for matching the query component of a DID URI. */
static readonly QUERY_PATTERN = `([?][^#]*)?`;
/** Regular expression pattern for matching the fragment component of a DID URI. */
static readonly FRAGMENT_PATTERN = `(#.*)?`;
/** Regular expression pattern for matching all of the components of a DID URI. */
static readonly DID_URI_PATTERN = new RegExp(
`^did:(?<method>${Did.METHOD_PATTERN}):(?<id>${Did.METHOD_ID_PATTERN})(?<path>${Did.PATH_PATTERN})(?<query>${Did.QUERY_PATTERN})(?<fragment>${Did.FRAGMENT_PATTERN})$`
);
/**
* A string representation of the DID.
*
* A DID is a URI composed of three parts: the scheme `did:`, a method identifier, and a unique,
* method-specific identifier specified by the DID method.
*
* @example
* did:dht:h4d3ixkwt6q5a455tucw7j14jmqyghdtbr6cpiz6on5oxj5bpr3o
*/
uri: string;
/**
* The name of the DID method.
*
* Examples of DID method names are `dht`, `jwk`, and `web`, among others.
*/
method: string;
/**
* The DID method identifier.
*
* @example
* h4d3ixkwt6q5a455tucw7j14jmqyghdtbr6cpiz6on5oxj5bpr3o
*/
id: string;
/**
* Optional path component of the DID URI.
*
* @example
* did:web:tbd.website/path
*/
path?: string;
/**
* Optional query component of the DID URI.
*
* @example
* did:web:tbd.website?versionId=1
*/
query?: string;
/**
* Optional fragment component of the DID URI.
*
* @example
* did:web:tbd.website#key-1
*/
fragment?: string;
/**
* Optional query parameters in the DID URI.
*
* @example
* did:web:tbd.website?service=files&relativeRef=/whitepaper.pdf
*/
params?: Record<string, string>;
/**
* Constructs a new `Did` instance from individual components.
*
* @param params - An object containing the parameters to be included in the DID URI.
* @param params.method - The name of the DID method.
* @param params.id - The DID method identifier.
* @param params.path - Optional. The path component of the DID URI.
* @param params.query - Optional. The query component of the DID URI.
* @param params.fragment - Optional. The fragment component of the DID URI.
* @param params.params - Optional. The query parameters in the DID URI.
*/
constructor({ method, id, path, query, fragment, params }: {
method: string,
id: string,
path?: string,
query?: string,
fragment?: string,
params?: Record<string, string>
}) {
this.uri = `did:${method}:${id}`;
this.method = method;
this.id = id;
this.path = path;
this.query = query;
this.fragment = fragment;
this.params = params;
}
/**
* Parses a DID URI string into its individual components.
*
* @example
* ```ts
* const did = Did.parse('did:example:123?service=agent&relativeRef=/credentials#degree');
*
* console.log(did.uri) // Output: 'did:example:123'
* console.log(did.method) // Output: 'example'
* console.log(did.id) // Output: '123'
* console.log(did.query) // Output: 'service=agent&relativeRef=/credentials'
* console.log(did.fragment) // Output: 'degree'
* console.log(did.params) // Output: { service: 'agent', relativeRef: '/credentials' }
* ```
*
* @params didUri - The DID URI string to be parsed.
* @returns A `Did` object representing the parsed DID URI, or `null` if the input string is not a valid DID URI.
*/
static parse(didUri: string): Did | null {
// Return null if the input string is empty or not provided.
if (!didUri) return null;
// Execute the regex pattern on the input string to extract URI components.
const match = Did.DID_URI_PATTERN.exec(didUri);
// If the pattern does not match, or if the required groups are not found, return null.
if (!match || !match.groups) return null;
// Extract the method, id, params, path, query, and fragment from the regex match groups.
const { method, id, path, query, fragment } = match.groups;
// Initialize a new Did object with the uri, method and id.
const did: Did = {
uri: `did:${method}:${id}`,
method,
id,
};
// If path is present, add it to the Did object.
if (path) did.path = path;
// If query is present, add it to the Did object, removing the leading '?'.
if (query) did.query = query.slice(1);
// If fragment is present, add it to the Did object, removing the leading '#'.
if (fragment) did.fragment = fragment.slice(1);
// If query params are present, parse them into a key-value object and add to the Did object.
if (query) {
const parsedParams = {} as Record<string, string>;
// Split the query string by '&' to get individual parameter strings.
const paramPairs = query.slice(1).split('&');
for (const pair of paramPairs) {
// Split each parameter string by '=' to separate keys and values.
const [key, value] = pair.split('=');
parsedParams[key] = value;
}
did.params = parsedParams;
}
return did;
}
}
+21
View File
@@ -0,0 +1,21 @@
export * from './types/did-core.js';
export * from './types/did-resolution.js';
export type * from './types/multibase.js';
export type * from './types/portable-did.js';
export * from './did.js';
export * from './did-error.js';
export * from './bearer-did.js';
export * from './methods/did-dht.js';
export * from './methods/did-ion.js';
export * from './methods/did-jwk.js';
export * from './methods/did-key.js';
export * from './methods/did-method.js';
export * from './methods/did-web.js';
export * from './resolver/resolver-cache-level.js';
export * from './resolver/resolver-cache-noop.js';
export * from './resolver/universal-resolver.js';
export * as utils from './utils.js';
File diff suppressed because it is too large Load Diff
+887
View File
@@ -0,0 +1,887 @@
import type { CryptoApi, Jwk, KeyIdentifier, KeyImporterExporter, KmsExportKeyParams, KmsImportKeyParams } from '@web5/crypto';
import type {
JwkEs256k,
IonDocumentModel,
IonPublicKeyModel,
IonPublicKeyPurpose,
} from '@decentralized-identity/ion-sdk';
import { IonDid, IonRequest } from '@decentralized-identity/ion-sdk';
import { LocalKeyManager, computeJwkThumbprint } from '@web5/crypto';
import type { PortableDid } from '../types/portable-did.js';
import type { DidCreateOptions, DidCreateVerificationMethod, DidRegistrationResult } from '../methods/did-method.js';
import type {
DidService,
DidDocument,
DidResolutionResult,
DidResolutionOptions,
DidVerificationMethod,
DidVerificationRelationship,
} from '../types/did-core.js';
import { Did } from '../did.js';
import { BearerDid } from '../bearer-did.js';
import { DidMethod } from '../methods/did-method.js';
import { DidError, DidErrorCode } from '../did-error.js';
import { getVerificationRelationshipsById } from '../utils.js';
import { EMPTY_DID_RESOLUTION_RESULT } from '../types/did-resolution.js';
/**
* Options for creating a Decentralized Identifier (DID) using the DID ION method.
*/
export interface DidIonCreateOptions<TKms> extends DidCreateOptions<TKms> {
/**
* Optional. The URI of a server involved in executing DID method operations. In the context of
* DID creation, the endpoint is expected to be a Sidetree node. If not specified, a default
* gateway node is used.
*/
gatewayUri?: string;
/**
* Optional. Determines whether the created DID should be published to a Sidetree node.
*
* If set to `true` or omitted, the DID is publicly discoverable. If `false`, the DID is not
* published and cannot be resolved by others. By default, newly created DIDs are published.
*
* @see {@link https://identity.foundation/sidetree/spec/#create | Sidetree Protocol Specification, § Create}
*
* @example
* ```ts
* const did = await DidIon.create({
* options: {
* publish: false
* };
* ```
*/
publish?: boolean;
/**
* Optional. An array of service endpoints associated with the DID.
*
* Services are used in DID documents to express ways of communicating with the DID subject or
* associated entities. A service can be any type of service the DID subject wants to advertise,
* including decentralized identity management services for further discovery, authentication,
* authorization, or interaction.
*
* @see {@link https://www.w3.org/TR/did-core/#services | DID Core Specification, § Services}
*
* @example
* ```ts
* const did = await DidIon.create({
* options: {
* services: [
* {
* id: 'dwn',
* type: 'DecentralizedWebNode',
* serviceEndpoint: ['https://example.com/dwn1', 'https://example/dwn2']
* }
* ]
* };
* ```
*/
services?: DidService[];
/**
* Optional. An array of verification methods to be included in the DID document.
*
* By default, a newly created DID ION document will contain a single Ed25519 verification method.
* Additional verification methods can be added to the DID document using the
* `verificationMethods` property.
*
* @see {@link https://www.w3.org/TR/did-core/#verification-methods | DID Core Specification, § Verification Methods}
*
* @example
* ```ts
* const did = await DidIon.create({
* options: {
* verificationMethods: [
* {
* algorithm: 'Ed25519',
* purposes: ['authentication', 'assertionMethod']
* },
* {
* algorithm: 'Ed25519',
* id: 'dwn-sig',
* purposes: ['authentication', 'assertionMethod']
* }
* ]
* };
* ```
*/
verificationMethods?: DidCreateVerificationMethod<TKms>[];
}
/**
* Represents the request model for managing DID documents within the ION network, according to the
* Sidetree protocol specification.
*/
export interface DidIonCreateRequest {
/** The type of operation to perform, which is always 'create' for a Create Operation. */
type: 'create';
/** Contains properties related to the initial state of the DID document. */
suffixData: {
/** A hash of the `delta` object, representing the initial changes to the DID document. */
deltaHash: string;
/** A commitment value used for future recovery operations, hashed for security. */
recoveryCommitment: string;
};
/** Details the changes to be applied to the DID document in this operation. */
delta: {
/** A commitment value used for the next update operation, hashed for security. */
updateCommitment: string;
/** An array of patch objects specifying the modifications to apply to the DID document. */
patches: {
/** The type of modification to perform (e.g., adding or removing public keys or service
* endpoints). */
action: string;
/** The document state or partial state to apply with this patch. */
document: IonDocumentModel;
}[];
}
}
/**
* Represents a {@link DidVerificationMethod | DID verification method} in the context of DID ION
* create, update, deactivate, and resolve operations.
*
* Unlike the DID Core standard {@link DidVerificationMethod} interface, this type is specific to
* the ION method operations and only includes the `id`, `publicKeyJwk`, and `purposes` properties:
* - The `id` property is optional and specifies the identifier fragment of the verification method.
* - The `publicKeyJwk` property is required and represents the public key in JWK format.
* - The `purposes` property is required and specifies the purposes for which the verification
* method can be used.
*
* @example
* ```ts
* const verificationMethod: DidIonVerificationMethod = {
* id : 'sig',
* publicKeyJwk : {
* kty : 'OKP',
* crv : 'Ed25519',
* x : 'o40shZrsco-CfEqk6mFsXfcP94ly3Az3gm84PzAUsXo',
* kid : 'BDp0xim82GswlxnPV8TPtBdUw80wkGIF8gjFbw1x5iQ',
* },
* purposes: ['authentication', 'assertionMethod']
* };
* ```
*/
export interface DidIonVerificationMethod {
/**
* Optionally specify the identifier fragment of the verification method.
*
* If not specified, the method's ID will be generated from the key's ID or thumbprint.
*
* @example
* ```ts
* const verificationMethod: DidIonVerificationMethod = {
* id: 'sig',
* ...
* };
* ```
*/
id?: string;
/**
* A public key in JWK format.
*
* A JSON Web Key (JWK) that conforms to {@link https://datatracker.ietf.org/doc/html/rfc7517 | RFC 7517}.
*
* @example
* ```ts
* const verificationMethod: DidIonVerificationMethod = {
* publicKeyJwk: {
* kty : "OKP",
* crv : "X25519",
* x : "7XdJtNmJ9pV_O_3mxWdn6YjiHJ-HhNkdYQARzVU_mwY",
* kid : "xtsuKULPh6VN9fuJMRwj66cDfQyLaxuXHkMlmAe_v6I"
* },
* ...
* };
* ```
*/
publicKeyJwk: Jwk;
/**
* Specify the purposes for which a verification method is intended to be used in a DID document.
*
* The `purposes` property defines the specific
* {@link DidVerificationRelationship | verification relationships} between the DID subject and
* the verification method. This enables the verification method to be utilized for distinct
* actions such as authentication, assertion, key agreement, capability delegation, and others. It
* is important for verifiers to recognize that a verification method must be associated with the
* relevant purpose in the DID document to be valid for that specific use case.
*
* @example
* ```ts
* const verificationMethod: DidIonVerificationMethod = {
* purposes: ['authentication', 'assertionMethod'],
* ...
* };
* ```
*/
purposes: (DidVerificationRelationship | keyof typeof DidVerificationRelationship)[];
}
/**
* `IonPortableDid` interface extends the {@link PortableDid} interface.
*
* It represents a Decentralized Identifier (DID) that is portable and can be used across different
* domains, including the ION specific recovery and update keys.
*/
export interface IonPortableDid extends PortableDid {
/** The JSON Web Key (JWK) used for recovery purposes. */
recoveryKey: Jwk;
/** The JSON Web Key (JWK) used for updating the DID. */
updateKey: Jwk;
}
/**
* Enumerates the types of keys that can be used in a DID ION document.
*
* The DID ION method supports various cryptographic key types. These key types are essential for
* the creation and management of DIDs and their associated cryptographic operations like signing
* and encryption.
*/
export enum DidIonRegisteredKeyType {
/**
* Ed25519: A public-key signature system using the EdDSA (Edwards-curve Digital Signature
* Algorithm) and Curve25519.
*/
Ed25519 = 'Ed25519',
/**
* secp256k1: A cryptographic curve used for digital signatures in a range of decentralized
* systems.
*/
secp256k1 = 'secp256k1',
/**
* secp256r1: Also known as P-256 or prime256v1, this curve is used for cryptographic operations
* and is widely supported in various cryptographic libraries and standards.
*/
secp256r1 = 'secp256r1',
/**
* X25519: A Diffie-Hellman key exchange algorithm using Curve25519.
*/
X25519 = 'X25519'
}
/**
* Private helper that maps algorithm identifiers to their corresponding DID ION
* {@link DidIonRegisteredKeyType | registered key type}.
*/
const AlgorithmToKeyTypeMap = {
Ed25519 : DidIonRegisteredKeyType.Ed25519,
ES256K : DidIonRegisteredKeyType.secp256k1,
ES256 : DidIonRegisteredKeyType.secp256r1,
'P-256' : DidIonRegisteredKeyType.secp256r1,
secp256k1 : DidIonRegisteredKeyType.secp256k1,
secp256r1 : DidIonRegisteredKeyType.secp256r1
} as const;
/**
* The default node to use as a gateway to the Sidetree newtork when anchoring, updating, and
* resolving DID documents.
*/
const DEFAULT_GATEWAY_URI = 'https://ion.tbd.engineering';
/**
* The `DidIon` class provides an implementation of the `did:ion` DID method.
*
* Features:
* - DID Creation: Create new `did:ion` DIDs.
* - DID Key Management: Instantiate a DID object from an existing key in a Key Management System
* (KMS). If supported by the KMS, a DID's key can be exported to a portable
* DID format.
* - DID Resolution: Resolve a `did:ion` to its corresponding DID Document stored in the Sidetree
* network.
* - Signature Operations: Sign and verify messages using keys associated with a DID.
*
* @see {@link https://identity.foundation/sidetree/spec/ | Sidetree Protocol Specification}
* @see {@link https://github.com/decentralized-identity/ion/blob/master/docs/design.md | ION Design Document}
*
* @example
* ```ts
* // DID Creation
* const did = await DidIon.create();
*
* // DID Creation with a KMS
* const keyManager = new LocalKeyManager();
* const did = await DidIon.create({ keyManager });
*
* // DID Resolution
* const resolutionResult = await DidIon.resolve({ did: did.uri });
*
* // Signature Operations
* const signer = await did.getSigner();
* const signature = await signer.sign({ data: new TextEncoder().encode('Message') });
* const isValid = await signer.verify({ data: new TextEncoder().encode('Message'), signature });
*
* // Key Management
*
* // Instantiate a DID object for a published DID with existing keys in a KMS
* const did = await DidIon.fromKeyManager({
* didUri: 'did:ion:EiAzB7K-xDIKc1csXo5HX2eNBoemK9feNhL3cKwfukYOug',
* keyManager
* });
*
* // Convert a DID object to a portable format
* const portableDid = await DidIon.toKeys({ did });
* ```
*/
export class DidIon extends DidMethod {
/**
* Name of the DID method, as defined in the DID ION specification.
*/
public static methodName = 'ion';
/**
* Creates a new DID using the `did:ion` method formed from a newly generated key.
*
* Notes:
* - If no `options` are given, by default a new Ed25519 key will be generated.
*
* @example
* ```ts
* // DID Creation
* const did = await DidIon.create();
*
* // DID Creation with a KMS
* const keyManager = new LocalKeyManager();
* const did = await DidIon.create({ keyManager });
* ```
*
* @param params - The parameters for the create operation.
* @param params.keyManager - Optionally specify a Key Management System (KMS) used to generate
* keys and sign data.
* @param params.options - Optional parameters that can be specified when creating a new DID.
* @returns A Promise resolving to a {@link BearerDid} object representing the new DID.
*/
public static async create<TKms extends CryptoApi | undefined = undefined>({
keyManager = new LocalKeyManager(),
options = {}
}: {
keyManager?: TKms;
options?: DidIonCreateOptions<TKms>;
} = {}): Promise<BearerDid> {
// Before processing the create operation, validate DID-method-specific requirements to prevent
// keys from being generated unnecessarily.
// Check 1: Validate that the algorithm for any given verification method is supported by the
// DID ION specification.
if (options.verificationMethods?.some(vm => !(vm.algorithm in AlgorithmToKeyTypeMap))) {
throw new Error('One or more verification method algorithms are not supported');
}
// Check 2: Validate that the ID for any given verification method is unique.
const methodIds = options.verificationMethods?.filter(vm => 'id' in vm).map(vm => vm.id);
if (methodIds && methodIds.length !== new Set(methodIds).size) {
throw new Error('One or more verification method IDs are not unique');
}
// Check 3: Validate that the required properties for any given services are present.
if (options.services?.some(s => !s.id || !s.type || !s.serviceEndpoint)) {
throw new Error('One or more services are missing required properties');
}
// If no verification methods were specified, generate a default Ed25519 verification method.
const defaultVerificationMethod: DidCreateVerificationMethod<TKms> = {
algorithm : 'Ed25519' as any,
purposes : ['authentication', 'assertionMethod', 'capabilityDelegation', 'capabilityInvocation']
};
const verificationMethodsToAdd: DidIonVerificationMethod[] = [];
// Generate random key material for additional verification methods, if any.
for (const vm of options.verificationMethods ?? [defaultVerificationMethod]) {
// Generate a random key for the verification method.
const keyUri = await keyManager.generateKey({ algorithm: vm.algorithm });
const publicKey = await keyManager.getPublicKey({ keyUri });
// Add the verification method to the DID document.
verificationMethodsToAdd.push({
id : vm.id,
publicKeyJwk : publicKey,
purposes : vm.purposes ?? ['authentication', 'assertionMethod', 'capabilityDelegation', 'capabilityInvocation']
});
}
// Generate a random key for the ION Recovery Key. Sidetree requires secp256k1 recovery keys.
const recoveryKeyUri = await keyManager.generateKey({ algorithm: DidIonRegisteredKeyType.secp256k1 });
const recoveryKey = await keyManager.getPublicKey({ keyUri: recoveryKeyUri });
// Generate a random key for the ION Update Key. Sidetree requires secp256k1 update keys.
const updateKeyUri = await keyManager.generateKey({ algorithm: DidIonRegisteredKeyType.secp256k1 });
const updateKey = await keyManager.getPublicKey({ keyUri: updateKeyUri });
// Compute the Long Form DID URI from the keys and services, if any.
const longFormDidUri = await DidIonUtils.computeLongFormDidUri({
recoveryKey,
updateKey,
services : options.services ?? [],
verificationMethods : verificationMethodsToAdd
});
// Expand the DID URI string to a DID document.
const { didDocument, didResolutionMetadata } = await DidIon.resolve(longFormDidUri, { gatewayUri: options.gatewayUri });
if (didDocument === null) {
throw new Error(`Unable to resolve DID during creation: ${didResolutionMetadata?.error}`);
}
// Create the BearerDid object, including the "Short Form" of the DID URI, the ION update and
// recovery keys, and specifying that the DID has not yet been published.
const did = new BearerDid({
uri : longFormDidUri,
document : didDocument,
metadata : {
published : false,
canonicalId : longFormDidUri.split(':', 3).join(':'),
recoveryKey,
updateKey
},
keyManager
});
// By default, publish the DID document to a Sidetree node unless explicitly disabled.
if (options.publish ?? true) {
const registrationResult = await DidIon.publish({ did, gatewayUri: options.gatewayUri });
did.metadata = registrationResult.didDocumentMetadata;
}
return did;
}
/**
* Given the W3C DID Document of a `did:ion` DID, return the verification method that will be used
* for signing messages and credentials. If given, the `methodId` parameter is used to select the
* verification method. If not given, the first verification method in the authentication property
* in the DID Document is used.
*
* @param params - The parameters for the `getSigningMethod` operation.
* @param params.didDocument - DID Document to get the verification method from.
* @param params.methodId - ID of the verification method to use for signing.
* @returns Verification method to use for signing.
*/
public static async getSigningMethod({ didDocument, methodId }: {
didDocument: DidDocument;
methodId?: string;
}): Promise<DidVerificationMethod> {
// Verify the DID method is supported.
const parsedDid = Did.parse(didDocument.id);
if (parsedDid && parsedDid.method !== this.methodName) {
throw new DidError(DidErrorCode.MethodNotSupported, `Method not supported: ${parsedDid.method}`);
}
// Get the verification method with either the specified ID or the first assertion method.
const verificationMethod = didDocument.verificationMethod?.find(
vm => vm.id === (methodId ?? didDocument.assertionMethod?.[0])
);
if (!(verificationMethod && verificationMethod.publicKeyJwk)) {
throw new DidError(DidErrorCode.InternalError, 'A verification method intended for signing could not be determined from the DID Document');
}
return verificationMethod;
}
/**
* Instantiates a {@link BearerDid} object for the DID ION method from a given {@link PortableDid}.
*
* This method allows for the creation of a `BearerDid` object using a previously created DID's
* key material, DID document, and metadata.
*
* @example
* ```ts
* // Export an existing BearerDid to PortableDid format.
* const portableDid = await did.export();
* // Reconstruct a BearerDid object from the PortableDid.
* const did = await DidIon.import({ portableDid });
* ```
*
* @param params - The parameters for the import operation.
* @param params.portableDid - The PortableDid object to import.
* @param params.keyManager - Optionally specify an external Key Management System (KMS) used to
* generate keys and sign data. If not given, a new
* {@link LocalKeyManager} instance will be created and
* used.
* @returns A Promise resolving to a `BearerDid` object representing the DID formed from the
* provided PortableDid.
* @throws An error if the DID document does not contain any verification methods or the keys for
* any verification method are missing in the key manager.
*/
public static async import({ portableDid, keyManager = new LocalKeyManager() }: {
keyManager?: CryptoApi & KeyImporterExporter<KmsImportKeyParams, KeyIdentifier, KmsExportKeyParams>;
portableDid: PortableDid;
}): Promise<BearerDid> {
// Verify the DID method is supported.
const parsedDid = Did.parse(portableDid.uri);
if (parsedDid?.method !== DidIon.methodName) {
throw new DidError(DidErrorCode.MethodNotSupported, `Method not supported`);
}
const did = await BearerDid.import({ portableDid, keyManager });
return did;
}
/**
* Publishes a DID to a Sidetree node, making it publicly discoverable and resolvable.
*
* This method handles the publication of a DID Document associated with a `did:ion` DID to a
* Sidetree node.
*
* @remarks
* - This method is typically invoked automatically during the creation of a new DID unless the
* `publish` option is set to `false`.
* - For existing, unpublished DIDs, it can be used to publish the DID Document to a Sidetree node.
* - The method relies on the specified Sidetree node to interface with the network.
*
* @param params - The parameters for the `publish` operation.
* @param params.did - The `BearerDid` object representing the DID to be published.
* @param params.gatewayUri - Optional. The URI of a server involved in executing DID
* method operations. In the context of publishing, the
* endpoint is expected to be a Sidetree node. If not
* specified, a default node is used.
* @returns A Promise resolving to a boolean indicating whether the publication was successful.
*
* @example
* ```ts
* // Generate a new DID and keys but explicitly disable publishing.
* const did = await DidIon.create({ options: { publish: false } });
* // Publish the DID to the Sidetree network.
* const isPublished = await DidIon.publish({ did });
* // `isPublished` is true if the DID was successfully published.
* ```
*/
public static async publish({ did, gatewayUri = DEFAULT_GATEWAY_URI }: {
did: BearerDid;
gatewayUri?: string;
}): Promise<DidRegistrationResult> {
// Construct an ION verification method made up of the id, public key, and purposes from each
// verification method in the DID document.
const verificationMethods: DidIonVerificationMethod[] = did.document.verificationMethod?.map(
vm => ({
id : vm.id,
publicKeyJwk : vm.publicKeyJwk!,
purposes : getVerificationRelationshipsById({ didDocument: did.document, methodId: vm.id })
})
) ?? [];
// Create the ION document.
const ionDocument = await DidIonUtils.createIonDocument({
services: did.document.service ?? [],
verificationMethods
});
// Construct the ION Create Operation request.
const createOperation = await DidIonUtils.constructCreateRequest({
ionDocument,
recoveryKey : did.metadata.recoveryKey,
updateKey : did.metadata.updateKey
});
try {
// Construct the URL of the SideTree node's operations endpoint.
const operationsUrl = DidIonUtils.appendPathToUrl({
baseUrl : gatewayUri,
path : `/operations`
});
// Submit the Create Operation to the operations endpoint.
const response = await fetch(operationsUrl, {
method : 'POST',
mode : 'cors',
headers : { 'Content-Type': 'application/json' },
body : JSON.stringify(createOperation)
});
// Return the result of processing the Create operation, including the updated DID metadata
// with the publishing result.
return {
didDocument : did.document,
didDocumentMetadata : {
...did.metadata,
published: response.ok,
},
didRegistrationMetadata: {}
};
} catch (error: any) {
return {
didDocument : null,
didDocumentMetadata : {
published: false,
},
didRegistrationMetadata: {
error : DidErrorCode.InternalError,
errorMessage : `Failed to publish DID document for: ${did.uri}`
}
};
}
}
/**
* Resolves a `did:ion` identifier to its corresponding DID document.
*
* This method performs the resolution of a `did:ion` DID, retrieving its DID Document from the
* Sidetree-based DID overlay network. The process involves querying a Sidetree node to retrieve
* the DID Document that corresponds to the given DID identifier.
*
* @remarks
* - If a `gatewayUri` option is not specified, a default node is used to access the Sidetree
* network.
* - It decodes the DID identifier and retrieves the associated DID Document and metadata.
* - In case of resolution failure, appropriate error information is returned.
*
* @example
* ```ts
* const resolutionResult = await DidIon.resolve('did:ion:example');
* ```
*
* @param didUri - The DID to be resolved.
* @param options - Optional parameters for resolving the DID. Unused by this DID method.
* @returns A Promise resolving to a {@link DidResolutionResult} object representing the result of the resolution.
*/
public static async resolve(didUri: string, options: DidResolutionOptions = {}): Promise<DidResolutionResult> {
// Attempt to parse the DID URI.
const parsedDid = Did.parse(didUri);
// If parsing failed, the DID is invalid.
if (!parsedDid) {
return {
...EMPTY_DID_RESOLUTION_RESULT,
didResolutionMetadata: { error: 'invalidDid' }
};
}
// If the DID method is not "ion", return an error.
if (parsedDid.method !== DidIon.methodName) {
return {
...EMPTY_DID_RESOLUTION_RESULT,
didResolutionMetadata: { error: 'methodNotSupported' }
};
}
// To execute the read method operation, use the given gateway URI or a default Sidetree node.
const gatewayUri = options?.gatewayUri ?? DEFAULT_GATEWAY_URI;
try {
// Construct the URL to be used in the resolution request.
const resolutionUrl = DidIonUtils.appendPathToUrl({
baseUrl : gatewayUri,
path : `/identifiers/${didUri}`
});
// Attempt to retrieve the DID document and metadata from the Sidetree node.
const response = await fetch(resolutionUrl);
// If the DID document was not found, return an error.
if (!response.ok) {
throw new DidError(DidErrorCode.NotFound, `Unable to find DID document for: ${didUri}`);
}
// If the DID document was retrieved successfully, return it.
const { didDocument, didDocumentMetadata } = await response.json() as DidResolutionResult;
return {
...EMPTY_DID_RESOLUTION_RESULT,
...didDocument && { didDocument },
didDocumentMetadata: {
published: didDocumentMetadata?.method?.published,
...didDocumentMetadata
}
};
} catch (error: any) {
// Rethrow any unexpected errors that are not a `DidError`.
if (!(error instanceof DidError)) throw new Error(error);
// Return a DID Resolution Result with the appropriate error code.
return {
...EMPTY_DID_RESOLUTION_RESULT,
didResolutionMetadata: {
error: error.code,
...error.message && { errorMessage: error.message }
}
};
}
}
}
/**
* The `DidIonUtils` class provides utility functions to support operations in the DID ION method.
*/
export class DidIonUtils {
/**
* Appends a specified path to a base URL, ensuring proper formatting of the resulting URL.
*
* This method is useful for constructing URLs for accessing various endpoints, such as Sidetree
* nodes in the ION network. It handles the nuances of URL path concatenation, including the
* addition or removal of leading/trailing slashes, to create a well-formed URL.
*
* @param params - The parameters for URL construction.
* @param params.baseUrl - The base URL to which the path will be appended.
* @param params.path - The path to append to the base URL.
* @returns The fully constructed URL string with the path appended to the base URL.
*/
public static appendPathToUrl({ baseUrl, path }: {
baseUrl: string;
path: string;
}): string {
const url = new URL(baseUrl);
url.pathname = url.pathname.endsWith('/') ? url.pathname : url.pathname + '/';
url.pathname += path.startsWith('/') ? path.substring(1) : path;
return url.toString();
}
/**
* Computes the Long Form DID URI given an ION DID's recovery key, update key, services, and
* verification methods.
*
* @param params - The parameters for computing the Long Form DID URI.
* @param params.recoveryKey - The ION Recovery Key.
* @param params.updateKey - The ION Update Key.
* @param params.services - An array of services associated with the DID.
* @param params.verificationMethods - An array of verification methods associated with the DID.
* @returns A Promise resolving to the Long Form DID URI.
*/
public static async computeLongFormDidUri({ recoveryKey, updateKey, services, verificationMethods }: {
recoveryKey: Jwk;
updateKey: Jwk;
services: DidService[];
verificationMethods: DidIonVerificationMethod[];
}): Promise<string> {
// Create the ION document.
const ionDocument = await DidIonUtils.createIonDocument({ services, verificationMethods });
// Normalize JWK to onnly include specific members and in lexicographic order.
const normalizedRecoveryKey = DidIonUtils.normalizeJwk(recoveryKey);
const normalizedUpdateKey = DidIonUtils.normalizeJwk(updateKey);
// Compute the Long Form DID URI.
const longFormDidUri = await IonDid.createLongFormDid({
document : ionDocument,
recoveryKey : normalizedRecoveryKey as JwkEs256k,
updateKey : normalizedUpdateKey as JwkEs256k
});
return longFormDidUri;
}
/**
* Constructs a Sidetree Create Operation request for a DID document within the ION network.
*
* This method prepares the necessary payload for submitting a Create Operation to a Sidetree
* node, encapsulating the details of the DID document, recovery key, and update key.
*
* @param params - Parameters required to construct the Create Operation request.
* @param params.ionDocument - The DID document model containing public keys and service endpoints.
* @param params.recoveryKey - The recovery public key in JWK format.
* @param params.updateKey - The update public key in JWK format.
* @returns A promise resolving to the ION Create Operation request model, ready for submission to a Sidetree node.
*/
public static async constructCreateRequest({ ionDocument, recoveryKey, updateKey }: {
ionDocument: IonDocumentModel,
recoveryKey: Jwk,
updateKey: Jwk
}): Promise<DidIonCreateRequest> {
// Create an ION DID create request operation.
const createRequest = await IonRequest.createCreateRequest({
document : ionDocument,
recoveryKey : DidIonUtils.normalizeJwk(recoveryKey) as JwkEs256k,
updateKey : DidIonUtils.normalizeJwk(updateKey) as JwkEs256k
}) as DidIonCreateRequest;
return createRequest;
}
/**
* Assembles an ION document model from provided services and verification methods
*
* This model serves as the foundation for a DID document in the ION network, facilitating the
* creation and management of decentralized identities. It translates service endpoints and
* public keys into a format compatible with the Sidetree protocol, ensuring the resulting DID
* document adheres to the required specifications for ION DIDs. This method is essential for
* constructing the payload needed to register or update DIDs within the ION network.
*
* @param params - The parameters containing the services and verification methods to include in the ION document.
* @param params.services - A list of service endpoints to be included in the DID document, specifying ways to interact with the DID subject.
* @param params.verificationMethods - A list of verification methods to be included, detailing the cryptographic keys and their intended uses within the DID document.
* @returns A Promise resolving to an `IonDocumentModel`, ready for use in Sidetree operations like DID creation and updates.
*/
public static async createIonDocument({ services, verificationMethods }: {
services: DidService[];
verificationMethods: DidIonVerificationMethod[]
}): Promise<IonDocumentModel> {
/**
* STEP 1: Convert verification methods to ION SDK format.
*/
const ionPublicKeys: IonPublicKeyModel[] = [];
for (const vm of verificationMethods) {
// Use the given ID, the key's ID, or the key's thumbprint as the verification method ID.
let methodId = vm.id ?? vm.publicKeyJwk.kid ?? await computeJwkThumbprint({ jwk: vm.publicKeyJwk });
methodId = `${methodId.split('#').pop()}`; // Remove fragment prefix, if any.
// Convert public key JWK to ION format.
const publicKey: IonPublicKeyModel = {
id : methodId,
publicKeyJwk : DidIonUtils.normalizeJwk(vm.publicKeyJwk),
purposes : vm.purposes as IonPublicKeyPurpose[],
type : 'JsonWebKey2020'
};
ionPublicKeys.push(publicKey);
}
/**
* STEP 2: Convert service entries, if any, to ION SDK format.
*/
const ionServices = services.map(service => ({
...service,
id: `${service.id.split('#').pop()}` // Remove fragment prefix, if any.
}));
/**
* STEP 3: Format as ION document.
*/
const ionDocumentModel: IonDocumentModel = {
publicKeys : ionPublicKeys,
services : ionServices
};
return ionDocumentModel;
}
/**
* Normalize the given JWK to include only specific members and in lexicographic order.
*
* @param jwk - The JWK to normalize.
* @returns The normalized JWK.
*/
private static normalizeJwk(jwk: Jwk): Jwk {
const keyType = jwk.kty;
let normalizedJwk: Jwk;
if (keyType === 'EC') {
normalizedJwk = { crv: jwk.crv, kty: jwk.kty, x: jwk.x, y: jwk.y };
} else if (keyType === 'oct') {
normalizedJwk = { k: jwk.k, kty: jwk.kty };
} else if (keyType === 'OKP') {
normalizedJwk = { crv: jwk.crv, kty: jwk.kty, x: jwk.x };
} else if (keyType === 'RSA') {
normalizedJwk = { e: jwk.e, kty: jwk.kty, n: jwk.n };
} else {
throw new Error(`Unsupported key type: ${keyType}`);
}
return normalizedJwk;
}
}

Some files were not shown because too many files have changed in this diff Show More