UNPKG

@nuwa-ai/identity-kit

Version:

SDK for NIP-1 Agent Single DID Multi-Key Model and NIP-3 CADOP (Custodian-Assisted DID Onboarding Protocol)

1,438 lines (1,426 loc) 181 kB
var __defProp = Object.defineProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; // src/errors/IdentityKitError.ts var IdentityKitErrorCode = /* @__PURE__ */ ((IdentityKitErrorCode2) => { IdentityKitErrorCode2["INVALID_CONFIGURATION"] = "INVALID_CONFIGURATION"; IdentityKitErrorCode2["ENVIRONMENT_NOT_SUPPORTED"] = "ENVIRONMENT_NOT_SUPPORTED"; IdentityKitErrorCode2["INITIALIZATION_FAILED"] = "INITIALIZATION_FAILED"; IdentityKitErrorCode2["DID_NOT_FOUND"] = "DID_NOT_FOUND"; IdentityKitErrorCode2["DID_INVALID_FORMAT"] = "DID_INVALID_FORMAT"; IdentityKitErrorCode2["DID_METHOD_NOT_SUPPORTED"] = "DID_METHOD_NOT_SUPPORTED"; IdentityKitErrorCode2["DID_CREATION_FAILED"] = "DID_CREATION_FAILED"; IdentityKitErrorCode2["DID_RESOLUTION_FAILED"] = "DID_RESOLUTION_FAILED"; IdentityKitErrorCode2["DID_NOT_SET"] = "DID_NOT_SET"; IdentityKitErrorCode2["DID_SERVICE_NOT_FOUND"] = "DID_SERVICE_NOT_FOUND"; IdentityKitErrorCode2["DID_VERIFICATION_METHOD_NOT_FOUND"] = "DID_VERIFICATION_METHOD_NOT_FOUND"; IdentityKitErrorCode2["VDR_NOT_AVAILABLE"] = "VDR_NOT_AVAILABLE"; IdentityKitErrorCode2["VDR_OPERATION_FAILED"] = "VDR_OPERATION_FAILED"; IdentityKitErrorCode2["VDR_NETWORK_ERROR"] = "VDR_NETWORK_ERROR"; IdentityKitErrorCode2["VDR_INVALID_RESPONSE"] = "VDR_INVALID_RESPONSE"; IdentityKitErrorCode2["KEY_NOT_FOUND"] = "KEY_NOT_FOUND"; IdentityKitErrorCode2["KEY_INVALID_FORMAT"] = "KEY_INVALID_FORMAT"; IdentityKitErrorCode2["KEY_GENERATION_FAILED"] = "KEY_GENERATION_FAILED"; IdentityKitErrorCode2["KEY_IMPORT_FAILED"] = "KEY_IMPORT_FAILED"; IdentityKitErrorCode2["KEY_STORAGE_ERROR"] = "KEY_STORAGE_ERROR"; IdentityKitErrorCode2["KEY_PERMISSION_DENIED"] = "KEY_PERMISSION_DENIED"; IdentityKitErrorCode2["KEY_VALIDATION_FAILED"] = "KEY_VALIDATION_FAILED"; IdentityKitErrorCode2["KEY_PRIVATE_KEY_NOT_AVAILABLE"] = "KEY_PRIVATE_KEY_NOT_AVAILABLE"; IdentityKitErrorCode2["KEY_DID_MISMATCH"] = "KEY_DID_MISMATCH"; IdentityKitErrorCode2["KEY_ID_MISMATCH"] = "KEY_ID_MISMATCH"; IdentityKitErrorCode2["KEY_TYPE_NOT_SUPPORTED"] = "KEY_TYPE_NOT_SUPPORTED"; IdentityKitErrorCode2["KEY_ALREADY_EXISTS"] = "KEY_ALREADY_EXISTS"; IdentityKitErrorCode2["SIGNING_FAILED"] = "SIGNING_FAILED"; IdentityKitErrorCode2["SIGNATURE_VERIFICATION_FAILED"] = "SIGNATURE_VERIFICATION_FAILED"; IdentityKitErrorCode2["SIGNER_NOT_AVAILABLE"] = "SIGNER_NOT_AVAILABLE"; IdentityKitErrorCode2["SIGNER_INVALID_DID"] = "SIGNER_INVALID_DID"; IdentityKitErrorCode2["SIGNER_NO_KEYS"] = "SIGNER_NO_KEYS"; IdentityKitErrorCode2["AUTH_INVALID_HEADER"] = "AUTH_INVALID_HEADER"; IdentityKitErrorCode2["AUTH_INVALID_BASE64"] = "AUTH_INVALID_BASE64"; IdentityKitErrorCode2["AUTH_INVALID_JSON"] = "AUTH_INVALID_JSON"; IdentityKitErrorCode2["AUTH_MISSING_SIGNATURE"] = "AUTH_MISSING_SIGNATURE"; IdentityKitErrorCode2["AUTH_TIMESTAMP_OUT_OF_WINDOW"] = "AUTH_TIMESTAMP_OUT_OF_WINDOW"; IdentityKitErrorCode2["AUTH_NONCE_REPLAYED"] = "AUTH_NONCE_REPLAYED"; IdentityKitErrorCode2["AUTH_DID_DOCUMENT_NOT_FOUND"] = "AUTH_DID_DOCUMENT_NOT_FOUND"; IdentityKitErrorCode2["AUTH_VERIFICATION_METHOD_NOT_FOUND"] = "AUTH_VERIFICATION_METHOD_NOT_FOUND"; IdentityKitErrorCode2["AUTH_INVALID_PUBLIC_KEY"] = "AUTH_INVALID_PUBLIC_KEY"; IdentityKitErrorCode2["AUTH_DID_MISMATCH"] = "AUTH_DID_MISMATCH"; IdentityKitErrorCode2["WEB_BROWSER_NOT_SUPPORTED"] = "WEB_BROWSER_NOT_SUPPORTED"; IdentityKitErrorCode2["WEB_STORAGE_NOT_AVAILABLE"] = "WEB_STORAGE_NOT_AVAILABLE"; IdentityKitErrorCode2["WEB_DEEPLINK_FAILED"] = "WEB_DEEPLINK_FAILED"; IdentityKitErrorCode2["WEB_CADOP_CONNECTION_FAILED"] = "WEB_CADOP_CONNECTION_FAILED"; IdentityKitErrorCode2["WEB_OAUTH_CALLBACK_FAILED"] = "WEB_OAUTH_CALLBACK_FAILED"; IdentityKitErrorCode2["WEB_NOT_CONNECTED"] = "WEB_NOT_CONNECTED"; IdentityKitErrorCode2["WEB_CALLBACK_FAILED"] = "WEB_CALLBACK_FAILED"; IdentityKitErrorCode2["REACT_NOT_AVAILABLE"] = "REACT_NOT_AVAILABLE"; IdentityKitErrorCode2["REACT_HOOK_MISUSE"] = "REACT_HOOK_MISUSE"; IdentityKitErrorCode2["CRYPTO_PROVIDER_NOT_FOUND"] = "CRYPTO_PROVIDER_NOT_FOUND"; IdentityKitErrorCode2["CRYPTO_OPERATION_FAILED"] = "CRYPTO_OPERATION_FAILED"; IdentityKitErrorCode2["CRYPTO_KEY_DERIVATION_FAILED"] = "CRYPTO_KEY_DERIVATION_FAILED"; IdentityKitErrorCode2["MULTIBASE_DECODE_FAILED"] = "MULTIBASE_DECODE_FAILED"; IdentityKitErrorCode2["MULTIBASE_ENCODE_FAILED"] = "MULTIBASE_ENCODE_FAILED"; IdentityKitErrorCode2["MULTIBASE_INVALID_FORMAT"] = "MULTIBASE_INVALID_FORMAT"; IdentityKitErrorCode2["SCOPE_VALIDATION_FAILED"] = "SCOPE_VALIDATION_FAILED"; IdentityKitErrorCode2["SCOPE_INVALID_FORMAT"] = "SCOPE_INVALID_FORMAT"; IdentityKitErrorCode2["VALIDATION_FAILED"] = "VALIDATION_FAILED"; IdentityKitErrorCode2["INVALID_INPUT_FORMAT"] = "INVALID_INPUT_FORMAT"; IdentityKitErrorCode2["DEEPLINK_INVALID_STATE"] = "DEEPLINK_INVALID_STATE"; IdentityKitErrorCode2["DEEPLINK_CALLBACK_FAILED"] = "DEEPLINK_CALLBACK_FAILED"; IdentityKitErrorCode2["STORAGE_QUOTA_EXCEEDED"] = "STORAGE_QUOTA_EXCEEDED"; IdentityKitErrorCode2["STORAGE_OPERATION_FAILED"] = "STORAGE_OPERATION_FAILED"; IdentityKitErrorCode2["SIGNER_CONVERSION_FAILED"] = "SIGNER_CONVERSION_FAILED"; IdentityKitErrorCode2["SIGNER_OPERATION_FAILED"] = "SIGNER_OPERATION_FAILED"; IdentityKitErrorCode2["PERMISSION_DENIED"] = "PERMISSION_DENIED"; IdentityKitErrorCode2["OPERATION_NOT_PERMITTED"] = "OPERATION_NOT_PERMITTED"; IdentityKitErrorCode2["OPERATION_NOT_SUPPORTED"] = "OPERATION_NOT_SUPPORTED"; IdentityKitErrorCode2["INVALID_PARAMETER"] = "INVALID_PARAMETER"; IdentityKitErrorCode2["INTERNAL_ERROR"] = "INTERNAL_ERROR"; IdentityKitErrorCode2["NETWORK_ERROR"] = "NETWORK_ERROR"; IdentityKitErrorCode2["TIMEOUT_ERROR"] = "TIMEOUT_ERROR"; return IdentityKitErrorCode2; })(IdentityKitErrorCode || {}); var IdentityKitError = class extends Error { constructor(code, message, options) { super(message); this.name = "IdentityKitError"; this.code = code; this.category = options?.category || this.inferCategory(code); this.details = options?.details; this.cause = options?.cause; if (Error.captureStackTrace) { Error.captureStackTrace(this, this.constructor); } if (options?.cause) { this.stack = `${this.stack} Caused by: ${options.cause.stack}`; } } /** * Infer error category from error code */ inferCategory(code) { if (code.startsWith("AUTH_")) return "authentication"; if (code.startsWith("DID_")) return "did"; if (code.startsWith("VDR_")) return "vdr"; if (code.startsWith("KEY_")) return "key-management"; if (code.startsWith("WEB_")) return "web"; if (code.startsWith("REACT_")) return "react"; if (code.startsWith("CRYPTO_")) return "crypto"; if (code.startsWith("MULTIBASE_")) return "multibase"; if (code.startsWith("SCOPE_") || code.startsWith("VALIDATION_")) return "validation"; if (code.startsWith("DEEPLINK_")) return "deeplink"; if (code.startsWith("STORAGE_")) return "storage"; if (code.startsWith("SIGNER_")) return "signer"; if (code.includes("SIGNING") || code.includes("SIGNATURE")) return "signing"; if (code.includes("NETWORK")) return "network"; if (code.includes("PERMISSION")) return "permission"; return "general"; } /** * Convert to a plain object for serialization */ toJSON() { return { name: this.name, code: this.code, category: this.category, message: this.message, details: this.details, stack: this.stack }; } /** * Get a user-friendly error message with suggestions */ getUserMessage() { const suggestions = this.getSuggestions(); let message = this.message; if (suggestions.length > 0) { message += "\n\nSuggestions:\n" + suggestions.map((s) => `\u2022 ${s}`).join("\n"); } return message; } /** * Get contextual suggestions based on error code */ getSuggestions() { switch (this.code) { case "WEB_BROWSER_NOT_SUPPORTED" /* WEB_BROWSER_NOT_SUPPORTED */: return [ "Use a modern browser that supports required Web APIs", "Check if you're running in a browser environment" ]; case "WEB_STORAGE_NOT_AVAILABLE" /* WEB_STORAGE_NOT_AVAILABLE */: return [ "Enable localStorage or IndexedDB in your browser", "Check if you're in private/incognito mode", "Consider using memory storage as fallback" ]; case "DID_METHOD_NOT_SUPPORTED" /* DID_METHOD_NOT_SUPPORTED */: return [ "Check if the DID method is registered with VDRRegistry", "Verify the DID format is correct" ]; case "VDR_NETWORK_ERROR" /* VDR_NETWORK_ERROR */: return [ "Check your network connection", "Verify the RPC URL is correct and accessible", "Check if the VDR service is running" ]; case "KEY_STORAGE_ERROR" /* KEY_STORAGE_ERROR */: return [ "Check browser storage permissions", "Verify storage quota is not exceeded", "Try clearing browser storage and retry" ]; case "REACT_NOT_AVAILABLE" /* REACT_NOT_AVAILABLE */: return [ "Ensure React is properly installed and imported", "Check if you're using the hook in a React component" ]; case "CRYPTO_PROVIDER_NOT_FOUND" /* CRYPTO_PROVIDER_NOT_FOUND */: return [ "Check if the key type is supported", "Verify the crypto provider factory configuration" ]; case "MULTIBASE_DECODE_FAILED" /* MULTIBASE_DECODE_FAILED */: return [ "Verify the encoded string format is correct", "Check if the multibase prefix is valid", "Ensure the input is not corrupted" ]; case "SCOPE_VALIDATION_FAILED" /* SCOPE_VALIDATION_FAILED */: return [ "Check the scope format: address::module::function", "Verify the address format is valid", "Ensure module and function names are correct" ]; case "DEEPLINK_INVALID_STATE" /* DEEPLINK_INVALID_STATE */: return [ "Check if the state parameter matches the stored value", "Verify the callback URL parameters are correct", "Ensure the session storage is available" ]; case "STORAGE_QUOTA_EXCEEDED" /* STORAGE_QUOTA_EXCEEDED */: return [ "Clear unused data from browser storage", "Check available storage quota", "Consider using a different storage strategy" ]; case "SIGNER_CONVERSION_FAILED" /* SIGNER_CONVERSION_FAILED */: return [ "Verify the signer implements the required interface", "Check if the key ID is available in the signer", "Ensure the DID account signer is properly configured" ]; default: return []; } } }; function createConfigurationError(message, details, cause) { return new IdentityKitError("INVALID_CONFIGURATION" /* INVALID_CONFIGURATION */, message, { category: "configuration", details, cause }); } function createDIDError(code, message, details, cause) { return new IdentityKitError(code, message, { category: "did", details, cause }); } function createVDRError(code, message, details, cause) { return new IdentityKitError(code, message, { category: "vdr", details, cause }); } function createKeyManagementError(code, message, details, cause) { return new IdentityKitError(code, message, { category: "key-management", details, cause }); } function createAuthenticationError(code, message, details, cause) { return new IdentityKitError(code, message, { category: "authentication", details, cause }); } function createWebError(code, message, details, cause) { return new IdentityKitError(code, message, { category: "web", details, cause }); } function createReactError(code, message, details, cause) { return new IdentityKitError(code, message, { category: "react", details, cause }); } function createCryptoError(code, message, details, cause) { return new IdentityKitError(code, message, { category: "crypto", details, cause }); } function createMultibaseError(code, message, details, cause) { return new IdentityKitError(code, message, { category: "multibase", details, cause }); } function createStorageError(code, message, details, cause) { return new IdentityKitError(code, message, { category: "storage", details, cause }); } function createValidationError(code, message, details, cause) { return new IdentityKitError(code, message, { category: "validation", details, cause }); } function createSignerError(code, message, details, cause) { return new IdentityKitError(code, message, { category: "signer", details, cause }); } function createDeepLinkError(code, message, details, cause) { return new IdentityKitError(code, message, { category: "deeplink", details, cause }); } function wrapUnknownError(error, context, code = "INTERNAL_ERROR" /* INTERNAL_ERROR */) { const originalError = error instanceof Error ? error : new Error(String(error)); return new IdentityKitError(code, `${context}: ${originalError.message}`, { cause: originalError, details: { context } }); } function isIdentityKitError(error) { return error instanceof IdentityKitError; } var AuthErrorCodeMapping = { INVALID_HEADER: "AUTH_INVALID_HEADER" /* AUTH_INVALID_HEADER */, INVALID_BASE64: "AUTH_INVALID_BASE64" /* AUTH_INVALID_BASE64 */, INVALID_JSON: "AUTH_INVALID_JSON" /* AUTH_INVALID_JSON */, MISSING_SIGNATURE: "AUTH_MISSING_SIGNATURE" /* AUTH_MISSING_SIGNATURE */, TIMESTAMP_OUT_OF_WINDOW: "AUTH_TIMESTAMP_OUT_OF_WINDOW" /* AUTH_TIMESTAMP_OUT_OF_WINDOW */, NONCE_REPLAYED: "AUTH_NONCE_REPLAYED" /* AUTH_NONCE_REPLAYED */, SIGNATURE_VERIFICATION_FAILED: "SIGNATURE_VERIFICATION_FAILED" /* SIGNATURE_VERIFICATION_FAILED */, DID_DOCUMENT_NOT_FOUND: "AUTH_DID_DOCUMENT_NOT_FOUND" /* AUTH_DID_DOCUMENT_NOT_FOUND */, VERIFICATION_METHOD_NOT_FOUND: "AUTH_VERIFICATION_METHOD_NOT_FOUND" /* AUTH_VERIFICATION_METHOD_NOT_FOUND */, INVALID_PUBLIC_KEY: "AUTH_INVALID_PUBLIC_KEY" /* AUTH_INVALID_PUBLIC_KEY */, DID_MISMATCH: "AUTH_DID_MISMATCH" /* AUTH_DID_MISMATCH */ }; // src/types/crypto.ts var KeyType = /* @__PURE__ */ ((KeyType7) => { KeyType7["ED25519"] = "Ed25519VerificationKey2020"; KeyType7["SECP256K1"] = "EcdsaSecp256k1VerificationKey2019"; KeyType7["ECDSAR1"] = "EcdsaSecp256r1VerificationKey2019"; return KeyType7; })(KeyType || {}); var KEY_TYPE = KeyType; function isKeyType(value) { return Object.values(KeyType).includes(value); } function toKeyType(value) { if (isKeyType(value)) { return value; } throw createValidationError( "KEY_TYPE_NOT_SUPPORTED" /* KEY_TYPE_NOT_SUPPORTED */, `Invalid key type: ${value}`, { value, supportedTypes: Object.values(KeyType) } ); } function roochSignatureSchemeToKeyType(scheme) { if (scheme === "Secp256k1") { return "EcdsaSecp256k1VerificationKey2019" /* SECP256K1 */; } else if (scheme === "ED25519") { return "Ed25519VerificationKey2020" /* ED25519 */; } else if (scheme === "EcdsaR1") { return "EcdsaSecp256r1VerificationKey2019" /* ECDSAR1 */; } throw createValidationError( "KEY_TYPE_NOT_SUPPORTED" /* KEY_TYPE_NOT_SUPPORTED */, `Unsupported Rooch signature scheme: ${scheme}`, { scheme, supportedSchemes: ["Secp256k1", "ED25519", "EcdsaR1"] } ); } function keyTypeToRoochSignatureScheme(keyType) { if (keyType === "EcdsaSecp256k1VerificationKey2019" /* SECP256K1 */) { return "Secp256k1"; } else if (keyType === "Ed25519VerificationKey2020" /* ED25519 */) { return "ED25519"; } else if (keyType === "EcdsaSecp256r1VerificationKey2019" /* ECDSAR1 */) { return "EcdsaR1"; } throw createValidationError( "KEY_TYPE_NOT_SUPPORTED" /* KEY_TYPE_NOT_SUPPORTED */, `Unsupported key type: ${keyType}`, { keyType, supportedTypes: Object.values(KeyType) } ); } function algorithmToKeyType(algorithm) { switch (algorithm) { case -8: return "Ed25519VerificationKey2020" /* ED25519 */; case -7: return "EcdsaSecp256r1VerificationKey2019" /* ECDSAR1 */; default: return void 0; } } function keyTypeToAlgorithm(keyType) { switch (keyType) { case "Ed25519VerificationKey2020" /* ED25519 */: return -8; case "EcdsaSecp256r1VerificationKey2019" /* ECDSAR1 */: return -7; default: return void 0; } } function getSupportedAlgorithms() { return [-8, -7]; } // src/cache/InMemoryLRUDIDDocumentCache.ts var InMemoryLRUDIDDocumentCache = class { constructor(maxEntries = 1e3) { this.capacity = maxEntries; this.map = /* @__PURE__ */ new Map(); } get(did) { if (!this.map.has(did)) return void 0; const value = this.map.get(did) ?? null; this.map.delete(did); this.map.set(did, value); return value; } set(did, doc) { if (this.map.has(did)) { this.map.delete(did); } else if (this.map.size >= this.capacity) { const lruKey = this.map.keys().next().value; if (lruKey !== void 0) { this.map.delete(lruKey); } } this.map.set(did, doc); } has(did) { return this.map.has(did); } delete(did) { this.map.delete(did); } clear() { this.map.clear(); } }; // src/vdr/VDRRegistry.ts var VDRRegistry = class _VDRRegistry { constructor() { this.vdrs = /* @__PURE__ */ new Map(); this.cache = new InMemoryLRUDIDDocumentCache(); } static getInstance() { if (!this.instance) { this.instance = new _VDRRegistry(); } return this.instance; } /** Register a VDR implementation for its DID method (e.g., 'key', 'rooch'). */ registerVDR(vdr) { this.vdrs.set(vdr.getMethod(), vdr); } /** Retrieve a previously registered VDR implementation by its method. */ getVDR(method) { return this.vdrs.get(method); } /** * Override the default cache implementation. * This allows developers to provide their own cache (e.g., Redis, browser storage). */ setCache(cache) { this.cache = cache; } /** Returns the currently configured cache instance. */ getCache() { return this.cache; } async resolveDID(did, options) { const method = did.split(":")[1]; const vdr = this.vdrs.get(method); if (!vdr) { throw createVDRError( "VDR_NOT_AVAILABLE" /* VDR_NOT_AVAILABLE */, `No VDR available for method: ${method}`, { method, availableMethods: Array.from(this.vdrs.keys()) } ); } if (!options?.forceRefresh) { const cached = this.cache.get(did); if (cached !== void 0) { return cached; } } const resolved = await vdr.resolve(did); this.cache.set(did, resolved); return resolved; } async createDID(method, creationRequest, options) { const vdr = this.vdrs.get(method); if (!vdr) { throw createVDRError( "VDR_NOT_AVAILABLE" /* VDR_NOT_AVAILABLE */, `No VDR available for method: ${method}`, { method, availableMethods: Array.from(this.vdrs.keys()) } ); } const result = await vdr.create(creationRequest, options); if (result.success && result.didDocument) { this.cache.set(result.didDocument.id, result.didDocument); } return result; } async createDIDViaCADOP(method, creationRequest, options) { const vdr = this.vdrs.get(method); if (!vdr) { throw createVDRError( "VDR_NOT_AVAILABLE" /* VDR_NOT_AVAILABLE */, `No VDR available for method: ${method}`, { method, availableMethods: Array.from(this.vdrs.keys()) } ); } const result = await vdr.createViaCADOP(creationRequest, options); if (result.success && result.didDocument) { this.cache.set(result.didDocument.id, result.didDocument); } return result; } async createDIDViaCADOPWithController(method, creationRequest, options) { const vdr = this.vdrs.get(method); if (!vdr) { throw createVDRError( "VDR_NOT_AVAILABLE" /* VDR_NOT_AVAILABLE */, `No VDR available for method: ${method}`, { method, availableMethods: Array.from(this.vdrs.keys()) } ); } const result = await vdr.createViaCADOPWithController(creationRequest, options); if (result.success && result.didDocument) { this.cache.set(result.didDocument.id, result.didDocument); } return result; } async exists(did) { const method = did.split(":")[1]; const vdr = this.vdrs.get(method); if (!vdr) { throw createVDRError( "VDR_NOT_AVAILABLE" /* VDR_NOT_AVAILABLE */, `No VDR available for method: ${method}`, { method, availableMethods: Array.from(this.vdrs.keys()) } ); } if (this.cache.has(did)) { const doc = this.cache.get(did); return doc !== null; } const exists = await vdr.exists(did); return exists; } }; // src/multibase/base.ts import { base58btc } from "multiformats/bases/base58"; import { base64pad, base64, base64url, base64urlpad } from "multiformats/bases/base64"; import { base16 } from "multiformats/bases/base16"; // src/utils/bytes.ts function stringToBytes(str) { if (typeof TextEncoder !== "undefined") { return new TextEncoder().encode(str); } if (typeof Buffer !== "undefined" && typeof Buffer.from === "function") { return Uint8Array.from(Buffer.from(str, "utf-8")); } throw createValidationError( "ENVIRONMENT_NOT_SUPPORTED" /* ENVIRONMENT_NOT_SUPPORTED */, "No TextEncoder or Buffer available in this environment.", { environment: typeof globalThis, textEncoderAvailable: typeof TextEncoder !== "undefined", bufferAvailable: typeof Buffer !== "undefined" } ); } function bytesToString(bytes) { if (typeof TextDecoder !== "undefined") { return new TextDecoder("utf-8").decode(bytes); } if (typeof Buffer !== "undefined" && typeof Buffer.from === "function") { return Buffer.from(bytes).toString("utf-8"); } throw createValidationError( "ENVIRONMENT_NOT_SUPPORTED" /* ENVIRONMENT_NOT_SUPPORTED */, "No TextDecoder or Buffer available in this environment.", { environment: typeof globalThis, textDecoderAvailable: typeof TextDecoder !== "undefined", bufferAvailable: typeof Buffer !== "undefined" } ); } function base64urlToBytes(base64url2) { const padding = base64url2.length % 4; const paddedBase64url = base64url2 + "=".repeat(padding === 0 ? 0 : 4 - padding); const base642 = paddedBase64url.replace(/-/g, "+").replace(/_/g, "/"); const binaryString = atob(base642); const bytes = new Uint8Array(binaryString.length); for (let i = 0; i < binaryString.length; i++) { bytes[i] = binaryString.charCodeAt(i); } return bytes; } var Bytes = { stringToBytes, bytesToString, base64urlToBytes }; // src/multibase/base.ts var ENCODER_MAP = { base58btc, base64pad, base64, base64url, base64urlpad, base16 }; var MultibaseCodec = class { /** * Generic encode * Example: `MultibaseCodec.encode(bytes, 'base64url')` */ static encode(data, base) { const encoder = ENCODER_MAP[base]; if (!encoder) { throw createMultibaseError( "MULTIBASE_ENCODE_FAILED" /* MULTIBASE_ENCODE_FAILED */, `Unsupported multibase: ${base}`, { base, supportedBases: Object.keys(ENCODER_MAP) } ); } const bytes = typeof data === "string" ? stringToBytes(data) : data; return encoder.encode(bytes); } /** * Encode bytes to base58btc format * @param bytes The bytes to encode * @returns base58btc encoded string with 'z' prefix */ static encodeBase58btc(bytes) { return this.encode(bytes, "base58btc"); } /** * Encode bytes to base64pad format * @param bytes The bytes to encode * @returns base64pad encoded string with 'M' prefix */ static encodeBase64pad(data) { return this.encode(data, "base64pad"); } /** * Encode bytes to base16 (hex) format * @param bytes The bytes to encode * @returns base16 encoded string with 'f' prefix */ static encodeBase16(bytes) { return this.encode(bytes, "base16"); } /** * Encode bytes to base64 format * @param bytes The bytes to encode * @returns base64 encoded string */ static encodeBase64(data) { return this.encode(data, "base64"); } /** * Encode bytes to base64url format (RFC4648 URL-safe, no padding) * @param bytes The bytes to encode * @returns base64url encoded string with 'u' prefix */ static encodeBase64url(data) { return this.encode(data, "base64url"); } /** * Encode bytes to base64urlpad format (URL-safe with padding) * @param bytes The bytes to encode * @returns base64urlpad encoded string with 'U' prefix */ static encodeBase64urlpad(data) { return this.encode(data, "base64urlpad"); } /** * Decode base58btc string to bytes * @param encoded The base58btc encoded string * @returns decoded bytes */ static decodeBase58btc(encoded) { return base58btc.decode(encoded); } /** * Decode base64pad string to bytes * @param encoded The base64pad encoded string * @returns decoded bytes */ static decodeBase64pad(encoded) { return base64pad.decode(encoded); } /** * Decode base16 string to bytes * @param encoded The base16 encoded string * @returns decoded bytes */ static decodeBase16(encoded) { return base16.decode(encoded); } /** * Decode base64 string to bytes * @param encoded The base64 encoded string * @returns decoded bytes */ static decodeBase64(encoded) { return base64.decode(encoded); } /** * Decode base64url string to bytes * @param encoded The base64url encoded string * @returns decoded bytes */ static decodeBase64url(encoded) { return base64url.decode(encoded); } /** * Decode base64url string to string * @param encoded The base64url encoded string * @returns decoded string */ static decodeBase64urlToString(encoded) { return bytesToString(this.decodeBase64url(encoded)); } /** * Decode base64urlpad string to bytes * @param encoded The base64urlpad encoded string * @returns decoded bytes */ static decodeBase64urlpad(encoded) { return base64urlpad.decode(encoded); } /** * Decode base64urlpad string to string * @param encoded The base64urlpad encoded string * @returns decoded string */ static decodeBase64urlpadToString(encoded) { return bytesToString(this.decodeBase64urlpad(encoded)); } /** * Decode multibase encoded string to bytes * After multiformats v9, there is no longer a single "universal base" object; * the official recommendation is to manually dispatch prefixes between the few *.decoder objects you use. * @param encoded The multibase encoded string * @returns decoded bytes */ static decode(encoded) { const prefix = encoded[0]; switch (prefix) { case "z": return base58btc.decode(encoded); case "M": return base64pad.decode(encoded); case "f": return base16.decode(encoded); case "m": return base64.decode(encoded); case "u": return base64url.decode(encoded); case "U": return base64urlpad.decode(encoded); default: throw createMultibaseError( "MULTIBASE_DECODE_FAILED" /* MULTIBASE_DECODE_FAILED */, `Unsupported multibase prefix: ${prefix}`, { prefix, supportedPrefixes: ["z", "M", "m", "u", "U", "f"] } ); } } }; // src/multibase/key.ts var KeyMultibaseCodec = class { /** * Encode public key with multicodec prefix * @param bytes The public key bytes * @param keyType The key type * @returns multibase encoded string */ static encodeWithType(bytes, keyType) { const expectedLength = this.getExpectedKeyLength(keyType); if (bytes.length !== expectedLength) { throw createValidationError( "INVALID_INPUT_FORMAT" /* INVALID_INPUT_FORMAT */, `Invalid key length for ${keyType}. Expected ${expectedLength} bytes, got ${bytes.length}`, { keyType, expectedLength, actualLength: bytes.length } ); } const prefix = this.getMulticodecPrefix(keyType); const prefixedKey = this.concatenateBytes(prefix, bytes); return MultibaseCodec.encodeBase58btc(prefixedKey); } /** * Decode multibase encoded key * @param encoded The multibase encoded string * @returns The key type and public key bytes */ static decodeWithType(encoded) { try { const decoded = MultibaseCodec.decodeBase58btc(encoded); if (decoded.length < 2) { throw createMultibaseError( "MULTIBASE_DECODE_FAILED" /* MULTIBASE_DECODE_FAILED */, "Invalid key format: too short", { encoded, minimumLength: 2, actualLength: decoded.length } ); } const keyType = this.extractKeyType(decoded); const bytes = this.extractBytes(decoded); const expectedLength = this.getExpectedKeyLength(keyType); if (bytes.length !== expectedLength) { throw createValidationError( "INVALID_INPUT_FORMAT" /* INVALID_INPUT_FORMAT */, `Invalid key length for ${keyType}. Expected ${expectedLength} bytes, got ${bytes.length}`, { keyType, expectedLength, actualLength: bytes.length } ); } return { keyType, bytes }; } catch (error) { if (error instanceof Error && error.message === "Non-base58btc character") { throw createMultibaseError( "MULTIBASE_DECODE_FAILED" /* MULTIBASE_DECODE_FAILED */, "Invalid multibase format", { encoded } ); } throw error; } } static getMulticodecPrefix(keyType) { switch (keyType) { case KEY_TYPE.ED25519: return this.ED25519_PREFIX; case KEY_TYPE.SECP256K1: return this.SECP256K1_PREFIX; case KEY_TYPE.ECDSAR1: return this.ECDSA_R1_PREFIX; default: throw createValidationError( "KEY_TYPE_NOT_SUPPORTED" /* KEY_TYPE_NOT_SUPPORTED */, `Unsupported key type: ${keyType}`, { keyType, supportedTypes: [KEY_TYPE.ED25519, KEY_TYPE.SECP256K1, KEY_TYPE.ECDSAR1] } ); } } static concatenateBytes(a, b) { const result = new Uint8Array(a.length + b.length); result.set(a); result.set(b, a.length); return result; } static extractKeyType(prefixedBytes) { if (prefixedBytes[0] === 237 && prefixedBytes[1] === 1) { return KEY_TYPE.ED25519; } else if (prefixedBytes[0] === 231 && prefixedBytes[1] === 1) { return KEY_TYPE.SECP256K1; } else if (prefixedBytes[0] === 18 && prefixedBytes[1] === 0) { return KEY_TYPE.ECDSAR1; } throw createMultibaseError( "MULTIBASE_DECODE_FAILED" /* MULTIBASE_DECODE_FAILED */, "Unknown key type prefix", { prefix: Array.from(prefixedBytes.slice(0, 2)) } ); } static extractBytes(prefixedBytes) { return prefixedBytes.slice(2); } static getExpectedKeyLength(keyType) { switch (keyType) { case KEY_TYPE.ED25519: return this.ED25519_KEY_LENGTH; case KEY_TYPE.SECP256K1: return this.SECP256K1_KEY_LENGTH; case KEY_TYPE.ECDSAR1: return this.ECDSA_R1_KEY_LENGTH; default: throw createValidationError( "KEY_TYPE_NOT_SUPPORTED" /* KEY_TYPE_NOT_SUPPORTED */, `Unsupported key type: ${keyType}`, { keyType, supportedTypes: [KEY_TYPE.ED25519, KEY_TYPE.SECP256K1, KEY_TYPE.ECDSAR1] } ); } } }; KeyMultibaseCodec.ED25519_PREFIX = new Uint8Array([237, 1]); KeyMultibaseCodec.SECP256K1_PREFIX = new Uint8Array([231, 1]); KeyMultibaseCodec.ECDSA_R1_PREFIX = new Uint8Array([18, 0]); KeyMultibaseCodec.ED25519_KEY_LENGTH = 32; KeyMultibaseCodec.SECP256K1_KEY_LENGTH = 33; KeyMultibaseCodec.ECDSA_R1_KEY_LENGTH = 33; // src/multibase/did.ts var DidKeyCodec = class { /** * Generate did:key from public key * @param publicKey The public key bytes * @param keyType The key type * @returns did:key identifier */ static generateDidKey(publicKey, keyType) { const multibase = KeyMultibaseCodec.encodeWithType(publicKey, keyType); return `did:key:${multibase}`; } /** * Parse did:key to get key type and public key * @param didKey The did:key identifier * @returns The key type and public key bytes */ static parseDidKey(didKey) { if (!didKey.startsWith("did:key:")) { throw createDIDError("DID_INVALID_FORMAT" /* DID_INVALID_FORMAT */, "Invalid did:key format", { didKey, expectedPrefix: "did:key:" }); } const multibase = didKey.substring(8); const { keyType, bytes } = KeyMultibaseCodec.decodeWithType(multibase); return { keyType, publicKey: bytes }; } }; // src/utils/did.ts function parseDid(did) { if (!did.startsWith("did:")) { throw createDIDError("DID_INVALID_FORMAT" /* DID_INVALID_FORMAT */, `Invalid DID: ${did}`, { did, reason: 'DID must start with "did:"' }); } const afterPrefix = did.slice(4); const methodEnd = afterPrefix.indexOf(":"); if (methodEnd === -1) { throw createDIDError( "DID_INVALID_FORMAT" /* DID_INVALID_FORMAT */, `Invalid DID \u2013 missing method/identifier separator: ${did}`, { did, reason: 'Missing method/identifier separator ":"' } ); } const method = afterPrefix.slice(0, methodEnd); const idPlusFrag = afterPrefix.slice(methodEnd + 1); if (!method || !idPlusFrag) { throw createDIDError("DID_INVALID_FORMAT" /* DID_INVALID_FORMAT */, `Invalid DID: ${did}`, { did, reason: "Empty method or identifier" }); } const hashIdx = idPlusFrag.indexOf("#"); return hashIdx === -1 ? { method, identifier: idPlusFrag } : { method, identifier: idPlusFrag.slice(0, hashIdx), fragment: idPlusFrag.slice(hashIdx + 1) }; } function extractMethod(did) { return parseDid(did).method; } function extractIdentifier(did) { return parseDid(did).identifier; } function extractFragment(idOrDid) { const idx = idOrDid.indexOf("#"); if (idx === -1) { throw createDIDError( "DID_INVALID_FORMAT" /* DID_INVALID_FORMAT */, `No fragment found in ${idOrDid}`, { idOrDid, reason: 'Missing fragment separator "#"' } ); } return idOrDid.slice(idx + 1); } var extractFragmentFromId = extractFragment; function buildDid(method, identifier) { return `did:${method}:${identifier}`; } function sameDid(a, b) { const pa = parseDid(a); const pb = parseDid(b); return pa.method === pb.method && pa.identifier === pb.identifier; } function getDidWithoutFragment(did) { const { method, identifier } = parseDid(did); return buildDid(method, identifier); } // src/utils/DebugLogger.ts var LEVEL_ORDER = { debug: 10, info: 20, warn: 30, error: 40, silent: 50 }; function detectInitialGlobalLevel() { if (typeof process !== "undefined" && process.env) { const envLevel = process.env.NUWA_LOG_LEVEL; if (envLevel && envLevel in LEVEL_ORDER) return envLevel; } if (typeof window !== "undefined" && window.__NUWA_LOG_LEVEL__) { const envLevel = window.__NUWA_LOG_LEVEL__; if (envLevel && envLevel in LEVEL_ORDER) return envLevel; } return "info"; } var _DebugLogger = class _DebugLogger { constructor(namespace) { this.namespace = namespace; this.levelOverridden = false; this.level = _DebugLogger.globalLevel; } /** Acquire (or create) a logger for the given namespace. */ static get(namespace) { if (!_DebugLogger.loggers.has(namespace)) { _DebugLogger.loggers.set(namespace, new _DebugLogger(namespace)); } return _DebugLogger.loggers.get(namespace); } /** Override global log level at runtime. */ static setGlobalLevel(level) { _DebugLogger.globalLevel = level; for (const logger3 of _DebugLogger.loggers.values()) { if (!logger3.levelOverridden) { logger3.level = level; } } } /** Read current global level. */ static getGlobalLevel() { return _DebugLogger.globalLevel; } /** Set default namespace used by static convenience methods. */ static setDefaultNamespace(namespace) { _DebugLogger.defaultNamespace = namespace; } // --------------------------------------------------------------------------- // Static convenience logging methods // --------------------------------------------------------------------------- /** * Log using the default namespace. Useful when callers don't need per-module loggers. * Example: DebugLogger.debug('hello') */ static debug(...args) { _DebugLogger.get(_DebugLogger.defaultNamespace).debug(...args); } static info(...args) { _DebugLogger.get(_DebugLogger.defaultNamespace).info(...args); } static warn(...args) { _DebugLogger.get(_DebugLogger.defaultNamespace).warn(...args); } static error(...args) { _DebugLogger.get(_DebugLogger.defaultNamespace).error(...args); } /** Override level for this logger only. */ setLevel(level) { this.level = level; this.levelOverridden = true; } // ------------------------------------------------------- // Logging helpers // ------------------------------------------------------- debug(...args) { this._log("debug", args); } info(...args) { this._log("info", args); } warn(...args) { this._log("warn", args); } error(...args) { this._log("error", args); } // prettier-ignore _log(level, args) { if (LEVEL_ORDER[level] < LEVEL_ORDER[this.level]) { return; } const prefix = `[${this.namespace}]`; switch (level) { case "debug": console.debug(prefix, ...args); break; case "info": console.info(prefix, ...args); break; case "warn": console.warn(prefix, ...args); break; case "error": console.error(prefix, ...args); break; } } }; // --------------------------------------------------------------------------- // Static section // --------------------------------------------------------------------------- _DebugLogger.globalLevel = detectInitialGlobalLevel(); _DebugLogger.loggers = /* @__PURE__ */ new Map(); _DebugLogger.defaultNamespace = "global"; var DebugLogger = _DebugLogger; // src/vdr/abstractVDR.ts var logger = DebugLogger.get("AbstractVDR"); var AbstractVDR = class { /** * Creates a new AbstractVDR instance * * @param method The DID method this VDR handles */ constructor(method) { this.method = method; } /** * Gets the DID method this VDR handles * * @returns The DID method string */ getMethod() { return this.method; } /** * Validates that a given DID matches the method this VDR handles * * @param did The DID to validate * @throws Error if the DID doesn't match this VDR's method */ validateDIDMethod(did) { const parsedDid = parseDid(did); if (parsedDid.method !== this.method) { throw createDIDError( "DID_INVALID_FORMAT" /* DID_INVALID_FORMAT */, `DID ${did} is not a valid did:${this.method} identifier`, { did, expectedMethod: this.method, actualMethod: parsedDid.method } ); } } /** * Validates a DID document's basic structure * * @param document The DID document to validate * @returns true if valid, throws an error otherwise */ validateDocument(document) { if (!document.id) { throw createValidationError( "VALIDATION_FAILED" /* VALIDATION_FAILED */, "DID document must have an id", { document } ); } this.validateDIDMethod(document.id); if (!document["@context"]) { throw createValidationError( "VALIDATION_FAILED" /* VALIDATION_FAILED */, "DID document must have a @context property", { document } ); } if (!document.verificationMethod || document.verificationMethod.length === 0) { throw createValidationError( "VALIDATION_FAILED" /* VALIDATION_FAILED */, "DID document must have at least one verification method", { document } ); } return true; } /** * Check if a key has a specific verification relationship in a DID document * * @param didDocument The DID document to check * @param keyId The ID of the verification method * @param relationship The verification relationship to check * @returns True if the key has the relationship */ hasVerificationRelationship(didDocument, keyId, relationship) { const relationshipArray = didDocument[relationship]; if (!relationshipArray) return false; return relationshipArray.some((item) => { if (typeof item === "string") { return item === keyId; } else if (typeof item === "object" && item.id) { return item.id === keyId; } return false; }); } /** * Validates if a key has permission to perform an operation * * @param didDocument The DID document * @param keyId The ID of the key * @param requiredRelationship The required verification relationship * @returns True if the key has permission */ validateKeyPermission(didDocument, keyId, requiredRelationship) { const keyExists = didDocument.verificationMethod?.some((vm) => vm.id === keyId); if (!keyExists) { logger.error(`Key ${keyId} not found in DID document`); return false; } const isPrimaryKey = didDocument.verificationMethod?.[0]?.id === keyId; if (isPrimaryKey) { return true; } const hasPermission = didDocument[requiredRelationship]?.includes(keyId); if (!hasPermission) { logger.error(`Key ${keyId} does not have ${requiredRelationship} permission`); return false; } return true; } /** * Default create implementation - throws not implemented error for base class * Subclasses must override this method to provide actual implementation */ async create(request, options) { throw createVDRError( "OPERATION_NOT_SUPPORTED" /* OPERATION_NOT_SUPPORTED */, `create method not implemented for ${this.method} VDR`, { method: this.method, operation: "create" } ); } /** * Default CADOP implementation - throws not implemented error */ async createViaCADOP(request, options) { throw createVDRError( "OPERATION_NOT_SUPPORTED" /* OPERATION_NOT_SUPPORTED */, `createViaCADOP not implemented for ${this.method} VDR`, { method: this.method, operation: "createViaCADOP" } ); } /** * Default CADOP with controller implementation - throws not implemented error */ async createViaCADOPWithController(request, options) { throw createVDRError( "OPERATION_NOT_SUPPORTED" /* OPERATION_NOT_SUPPORTED */, `createViaCADOPWithController not implemented for ${this.method} VDR`, { method: this.method, operation: "createViaCADOPWithController" } ); } /** * Build DID Document from creation request */ buildDIDDocumentFromRequest(request) { const did = request.preferredDID; const controllerForVM = Array.isArray(request.controller) ? request.controller[0] : request.controller || did; const verificationMethod = { id: `${did}#account-key`, type: request.keyType || "EcdsaSecp256k1VerificationKey2019", controller: controllerForVM, publicKeyMultibase: request.publicKeyMultibase }; const didDocument = { "@context": ["https://www.w3.org/ns/did/v1"], id: did, controller: request.controller ? Array.isArray(request.controller) ? request.controller : [request.controller] : [did], verificationMethod: [verificationMethod, ...request.additionalVerificationMethods || []], service: request.initialServices || [] }; const relationships = request.initialRelationships || [ "authentication", "assertionMethod", "capabilityInvocation", "capabilityDelegation" ]; const vmId = verificationMethod.id; relationships.forEach((rel) => { if (!didDocument[rel]) { didDocument[rel] = []; } didDocument[rel].push(vmId); }); return didDocument; } /** * Checks if a DID exists in the registry * Default implementation tries to resolve and checks if result is not null */ async exists(did) { try { const doc = await this.resolve(did); return doc !== null; } catch (error) { return false; } } /** * Add a verification method to a DID document * Default implementation that should be overridden by specific VDR implementations */ async addVerificationMethod(did, verificationMethod, relationships, options) { throw createVDRError( "OPERATION_NOT_SUPPORTED" /* OPERATION_NOT_SUPPORTED */, `addVerificationMethod not implemented for ${this.method} VDR`, { method: this.method, operation: "addVerificationMethod" } ); } /** * Remove a verification method from a DID document * Default implementation that should be overridden by specific VDR implementations */ async removeVerificationMethod(did, id, options) { throw createVDRError( "OPERATION_NOT_SUPPORTED" /* OPERATION_NOT_SUPPORTED */, `removeVerificationMethod not implemented for ${this.method} VDR`, { method: this.method, operation: "removeVerificationMethod" } ); } /** * Add a service to a DID document * Default implementation that should be overridden by specific VDR implementations */ async addService(did, service, options) { throw createVDRError( "OPERATION_NOT_SUPPORTED" /* OPERATION_NOT_SUPPORTED */, `addService not implemented for ${this.method} VDR`, { method: this.method, operation: "addService" } ); } /** * Remove a service from a DID document * Default implementation that should be overridden by specific VDR implementations */ async removeService(did, id, options) { throw createVDRError( "OPERATION_NOT_SUPPORTED" /* OPERATION_NOT_SUPPORTED */, `removeService not implemented for ${this.method} VDR`, { method: this.method, operation: "removeService" } ); } /** * Update verification relationships for a verification method * Default implementation that should be overridden by specific VDR implementations */ async updateRelationships(did, id, add, remove, options) { throw createVDRError( "OPERATION_NOT_SUPPORTED" /* OPERATION_NOT_SUPPORTED */, `updateRelationships not implemented for ${this.method} VDR`, { method: this.method, operation: "updateRelationships" } ); } /** * Update the controller of a DID document * Default implementation that should be overridden by specific VDR implementations */ async updateController(did, controller, options) { throw createVDRError( "OPERATION_NOT_SUPPORTED" /* OPERATION_NOT_SUPPORTED */, `updateController not implemented for ${this.method} VDR`, { method: this.method, operation: "updateController" } ); } /** * Validates options for update operations and ensures proper permissions * * @param did The DID being operated on * @param document The resolved DID document * @param keyId The key ID used for signing * @param requiredRelationship The required verification relationship for this operation * @throws Error if validation fails */ async validateUpdateOperation(did, document, keyId, requiredRelationship) { this.validateDIDMethod(did); if (!document) { throw createDIDError("DID_NOT_FOUND" /* DID_NOT_FOUND */, `DID document ${did} not found`, { did, operation: "validateUpdateOperation" }); } if (!this.validateKeyPermission(document, keyId, requiredRelationship)) { throw createValidationError( "KEY_PERMISSION_DENIED" /* KEY_PERMISSION_DENIED */, `Key ${keyId} does not have ${requiredRelationship} permission required for this operation`, { keyId, requiredRelationship, did } ); } return document; } /** * Validates that inputs to addVerificationMethod are correct * * @param did The DID being operated on * @param verificationMethod The verification method to validate * @param document The current DID document * @throws Error if validation fails */ validateVerificationMethod(did, verificationMethod, document) { if (!verificationMethod.id.startsWith(did)) { throw createValidationError( "VALIDATION_FAILED" /* VALIDATION_FAILED */, `Verification method ID ${verificationMethod.id} must start with DID ${did}`, { verificationMethodId: verificationMethod.id, did } ); } if (document.verificationMethod?.some((vm) => vm.id === verificationMethod.id)) { throw createValidationError( "VALIDATION_FAILED" /* VALIDATION_FAILED */, `Verification method ${verificationMethod.id} already exists`, { verificationMethodId: verificationMethod.id, did } ); } if (!verificationMethod.type) { throw createValidationError( "VALIDATION_FAILED" /* VALIDATION_FAILED */, "Verification method must have a type", { verificationMethod, did } ); } if (!verificationMethod.controller) { throw createValidationError( "VALIDATION_FAILED" /* VALIDATION_FAILED */, "Verification method must have a controller", { verificationMethod, did } ); } if (!verificationMethod.publicKeyMultiba