@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,523 lines (1,500 loc) • 180 kB
JavaScript
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/testHelpers/index.ts
var testHelpers_exports = {};
__export(testHelpers_exports, {
RoochLocalNode: () => RoochLocalNode,
RoochTestUtils: () => RoochTestUtils,
TestEnv: () => TestEnv,
bootstrapRoochTestEnv: () => bootstrapRoochTestEnv,
createCadopCustodian: () => createCadopCustodian,
createDidViaCadop: () => createDidViaCadop,
createSelfDid: () => createSelfDid,
ensureRoochReady: () => ensureRoochReady,
startLocalRoochNode: () => startLocalRoochNode
});
module.exports = __toCommonJS(testHelpers_exports);
// src/testHelpers/env.ts
var import_rooch_sdk5 = require("@roochnetwork/rooch-sdk");
// 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/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/errors/IdentityKitError.ts
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 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 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 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
});
}
// 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/vdr/roochVDR.ts
var import_rooch_sdk4 = require("@roochnetwork/rooch-sdk");
// src/multibase/base.ts
var import_base58 = require("multiformats/bases/base58");
var import_base64 = require("multiformats/bases/base64");
var import_base16 = require("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;
}
// src/multibase/base.ts
var ENCODER_MAP = {
base58btc: import_base58.base58btc,
base64pad: import_base64.base64pad,
base64: import_base64.base64,
base64url: import_base64.base64url,
base64urlpad: import_base64.base64urlpad,
base16: import_base16.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 import_base58.base58btc.decode(encoded);
}
/**
* Decode base64pad string to bytes
* @param encoded The base64pad encoded string
* @returns decoded bytes
*/
static decodeBase64pad(encoded) {
return import_base64.base64pad.decode(encoded);
}
/**
* Decode base16 string to bytes
* @param encoded The base16 encoded string
* @returns decoded bytes
*/
static decodeBase16(encoded) {
return import_base16.base16.decode(encoded);
}
/**
* Decode base64 string to bytes
* @param encoded The base64 encoded string
* @returns decoded bytes
*/
static decodeBase64(encoded) {
return import_base64.base64.decode(encoded);
}
/**
* Decode base64url string to bytes
* @param encoded The base64url encoded string
* @returns decoded bytes
*/
static decodeBase64url(encoded) {
return import_base64.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 import_base64.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 import_base58.base58btc.decode(encoded);
case "M":
return import_base64.base64pad.decode(encoded);
case "f":
return import_base16.base16.decode(encoded);
case "m":
return import_base64.base64.decode(encoded);
case "u":
return import_base64.base64url.decode(encoded);
case "U":
return import_base64.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/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) }
);
}
// 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/crypto/providers/ed25519.ts
function getCrypto() {
if (typeof globalThis !== "undefined" && globalThis.crypto) {
return globalThis.crypto;
}
throw createCryptoError(
"ENVIRONMENT_NOT_SUPPORTED" /* ENVIRONMENT_NOT_SUPPORTED */,
"Web Crypto API is not available in the current runtime",
{ environment: typeof globalThis, cryptoAvailable: false }
);
}
var Ed25519Provider = class {
constructor() {
this.crypto = getCrypto();
}
async generateKeyPair() {
const generated = await this.crypto.subtle.generateKey(
{
name: "Ed25519"
},
true,
["sign", "verify"]
);
if (!("publicKey" in generated)) {
throw createCryptoError(
"CRYPTO_OPERATION_FAILED" /* CRYPTO_OPERATION_FAILED */,
"Ed25519 generateKey did not return a key pair",
{ keyType: "Ed25519", operation: "generateKeyPair" }
);
}
const { publicKey, privateKey } = generated;
const exportedPublic = new Uint8Array(await this.crypto.subtle.exportKey("raw", publicKey));
const exportedPrivate = new Uint8Array(await this.crypto.subtle.exportKey("pkcs8", privateKey));
return {
publicKey: exportedPublic,
privateKey: exportedPrivate
};
}
async sign(data, privateKey) {
let key;
if (privateKey instanceof Uint8Array) {
key = await this.crypto.subtle.importKey(
"pkcs8",
privateKey,
{
name: "Ed25519"
},
false,
["sign"]
);
} else {
key = privateKey;
}
const signature = await this.crypto.subtle.sign("Ed25519", key, data);
return new Uint8Array(signature);
}
async verify(data, signature, publicKey) {
let key;
if (publicKey instanceof Uint8Array) {
key = await this.crypto.subtle.importKey(
"raw",
publicKey,
{
name: "Ed25519"
},
false,
["verify"]
);
} else {
key = await this.crypto.subtle.importKey(
"jwk",
publicKey,
{
name: "Ed25519"
},
false,
["verify"]
);
}
return await this.crypto.subtle.verify("Ed25519", key, signature, data);
}
getKeyType() {
return KEY_TYPE.ED25519;
}
async derivePublicKey(privateKey) {
const cryptoKey = await this.crypto.subtle.importKey(
"pkcs8",
privateKey,
{ name: "Ed25519" },
true,
["sign"]
);
const jwk = await this.crypto.subtle.exportKey("jwk", cryptoKey);
if (!jwk.x) {
throw createCryptoError(
"CRYPTO_KEY_DERIVATION_FAILED" /* CRYPTO_KEY_DERIVATION_FAILED */,
"Failed to derive public key from private key",
{ keyType: "Ed25519", operation: "derivePublicKey" }
);
}
const publicKeyBytes = base64urlToBytes(jwk.x);
return publicKeyBytes;
}
};
// src/crypto/providers/secp256k1.ts
var import_secp256k1 = require("@noble/curves/secp256k1");
var import_sha256 = require("@noble/hashes/sha256");
var Secp256k1Provider = class {
async generateKeyPair() {
const privateKey = import_secp256k1.secp256k1.utils.randomPrivateKey();
const publicKey = import_secp256k1.secp256k1.getPublicKey(privateKey, true);
return {
publicKey,
privateKey
};
}
async sign(data, privateKey) {
if (privateKey instanceof CryptoKey) {
throw createCryptoError(
"OPERATION_NOT_SUPPORTED" /* OPERATION_NOT_SUPPORTED */,
"CryptoKey is not supported for Secp256k1 signing",
{ keyType: "Secp256k1", operation: "sign", privateKeyType: "CryptoKey" }
);
}
const msgHash = (0, import_sha256.sha256)(data);
const signature = import_secp256k1.secp256k1.sign(msgHash, privateKey);
return signature.toCompactRawBytes();
}
async verify(data, signature, publicKey) {
if (!(publicKey instanceof Uint8Array)) {
throw createCryptoError(
"OPERATION_NOT_SUPPORTED" /* OPERATION_NOT_SUPPORTED */,
"JsonWebKey is not supported for Secp256k1 verification",
{ keyType: "Secp256k1", operation: "verify", publicKeyType: "JsonWebKey" }
);
}
const msgHash = (0, import_sha256.sha256)(data);
return import_secp256k1.secp256k1.verify(signature, msgHash, publicKey);
}
getKeyType() {
return KEY_TYPE.SECP256K1;
}
async derivePublicKey(privateKey) {
return import_secp256k1.secp256k1.getPublicKey(privateKey, true);
}
};
// src/crypto/providers/ecdsa_r1.ts
var import_p256 = require("@noble/curves/p256");
var import_utils = require("@noble/curves/abstract/utils");
function getCrypto2() {
if (typeof globalThis !== "undefined" && globalThis.crypto) {
return globalThis.crypto;
}
throw createCryptoError(
"ENVIRONMENT_NOT_SUPPORTED" /* ENVIRONMENT_NOT_SUPPORTED */,
"Web Crypto API is not available in the current runtime",
{ environment: typeof globalThis, cryptoAvailable: false }
);
}
var EcdsaR1Provider = class {
constructor() {
this.crypto = getCrypto2();
}
async generateKeyPair() {
const generated = await this.crypto.subtle.generateKey(
{
name: "ECDSA",
namedCurve: "P-256"
},
true,
["sign", "verify"]
);
if (!("publicKey" in generated)) {
throw createCryptoError(
"CRYPTO_OPERATION_FAILED" /* CRYPTO_OPERATION_FAILED */,
"ECDSA P-256 generateKey did not return a key pair",
{ keyType: "ECDSA-R1", operation: "generateKeyPair" }
);
}
const { publicKey, privateKey } = generated;
const exportedPublic = new Uint8Array(await this.crypto.subtle.exportKey("raw", publicKey));
const exportedPrivate = new Uint8Array(await this.crypto.subtle.exportKey("pkcs8", privateKey));
const compressedPublicKey = this.compressPublicKey(exportedPublic);
return {
publicKey: compressedPublicKey,
privateKey: exportedPrivate
};
}
compressPublicKey(publicKey) {
if (publicKey.length !== 65) {
throw createValidationError(
"INVALID_INPUT_FORMAT" /* INVALID_INPUT_FORMAT */,
`Invalid public key length. Expected 65 bytes, got ${publicKey.length}`,
{ expectedLength: 65, actualLength: publicKey.length, keyType: "ECDSA-R1" }
);
}
if (publicKey[0] !== 4) {
throw createValidationError(
"INVALID_INPUT_FORMAT" /* INVALID_INPUT_FORMAT */,
"Invalid public key format. Expected uncompressed format (0x04)",
{ actualPrefix: publicKey[0], expectedPrefix: 4, keyType: "ECDSA-R1" }
);
}
const x = publicKey.slice(1, 33);
const y = publicKey.slice(33, 65);
const compressedFormat = y[31] % 2 === 0 ? 2 : 3;
const compressed = new Uint8Array(33);
compressed[0] = compressedFormat;
compressed.set(x, 1);
return compressed;
}
decompressPublicKey(compressedKey) {
if (compressedKey.length !== 33) {
throw createValidationError(
"INVALID_INPUT_FORMAT" /* INVALID_INPUT_FORMAT */,
`Invalid compressed public key length. Expected 33 bytes, got ${compressedKey.length}`,
{ expectedLength: 33, actualLength: compressedKey.length, keyType: "ECDSA-R1" }
);
}
const format = compressedKey[0];
if (format !== 2 && format !== 3) {
throw createValidationError(
"INVALID_INPUT_FORMAT" /* INVALID_INPUT_FORMAT */,
"Invalid compressed public key format. Expected 0x02 or 0x03",
{ actualPrefix: compressedKey[0], expectedPrefixes: [2, 3], keyType: "ECDSA-R1" }
);
}
try {
const point = import_p256.p256.ProjectivePoint.fromHex(compressedKey);
const x = point.x;
const y = point.y;
const xBytes = (0, import_utils.hexToBytes)(x.toString(16).padStart(64, "0"));
const yBytes = (0, import_utils.hexToBytes)(y.toString(16).padStart(64, "0"));
const decompressed = new Uint8Array(65);
decompressed[0] = 4;
decompressed.set(xBytes, 1);
decompressed.set(yBytes, 33);
return decompressed;
} catch (err) {
const error = err;
throw createCryptoError(
"CRYPTO_OPERATION_FAILED" /* CRYPTO_OPERATION_FAILED */,
`Failed to decompress public key: ${error.message}`,
{ keyType: "ECDSA-R1", operation: "decompressPublicKey", originalError: error.message }
);
}
}
async sign(data, privateKey) {
let key;
if (privateKey instanceof Uint8Array) {
key = await this.crypto.subtle.importKey(
"pkcs8",
privateKey,
{
name: "ECDSA",
namedCurve: "P-256"
},
false,
["sign"]
);
} else {
key = privateKey;
}
const signature = await this.crypto.subtle.sign(
{
name: "ECDSA",
hash: { name: "SHA-256" }
},
key,
data
);
return new Uint8Array(signature);
}
convertDERSignatureToRaw(derSignature) {
const firstByte = derSignature[0];
if (firstByte === 48) {
try {
const sig = import_p256.p256.Signature.fromDER(derSignature);
return sig.toCompactRawBytes();
} catch (e) {
throw createValidationError(
"INVALID_INPUT_FORMAT" /* INVALID_INPUT_FORMAT */,
"Invalid DER signature",
{ keyType: "ECDSA-R1", operation: "parseDERSignature" }
);
}
}
return derSignature;
}
convertRawToDER(raw) {
if (raw.length !== 64) return raw;
const r = (0, import_utils.bytesToHex)(raw.slice(0, 32));
const s = (0, import_utils.bytesToHex)(raw.slice(32, 64));
const der = import_p256.p256.Signature.fromCompact((0, import_utils.hexToBytes)(r + s)).toDERHex();
return (0, import_utils.hexToBytes)(der);
}
async verify(data, signature, publicKey) {
let key;
if (publicKey instanceof Uint8Array) {
const decompressedKey = this.decompressPublicKey(publicKey);
key = await this.crypto.subtle.importKey(
"raw",
decompressedKey,
{
name: "ECDSA",
namedCurve: "P-256"
},
false,
["verify"]
);
} else {
key = await this.crypto.subtle.importKey(
"jwk",
publicKey,
{
name: "ECDSA",
namedCurve: "P-256"
},
false,
["verify"]
);
}
return await this.crypto.subtle.verify(
{
name: "ECDSA",
hash: { name: "SHA-256" }
},
key,
signature,
data
);
}
getKeyType() {
return KEY_TYPE.ECDSAR1;
}
async derivePublicKey(privateKey) {
const cryptoKey = await this.crypto.subtle.importKey(
"pkcs8",
privateKey,
{ name: "ECDSA", namedCurve: "P-256" },
true,
["sign"]
);
const jwk = await this.crypto.subtle.exportKey("jwk", cryptoKey);
if (!jwk.x || !jwk.y) {
throw createCryptoError(
"CRYPTO_KEY_DERIVATION_FAILED" /* CRYPTO_KEY_DERIVATION_FAILED */,
"Failed to derive public key from private key",
{ keyType: "ECDSA-R1", operation: "derivePublicKey" }
);
}
const x = base64urlToBytes(jwk.x);
const y = base64urlToBytes(jwk.y);
const uncompressed = new Uint8Array(65);
uncompressed[0] = 4;
uncompressed.set(x, 1);
uncompressed.set(y, 33);
return this.compressPublicKey(uncompressed);
}
};
// src/crypto/factory.ts
var DefaultCryptoProviderFactory = class {
constructor() {
this.providers = /* @__PURE__ */ new Map();
this.providers.set(KEY_TYPE.ED25519, new Ed25519Provider());
this.providers.set(KEY_TYPE.SECP256K1, new Secp256k1Provider());
this.providers.set(KEY_TYPE.ECDSAR1, new EcdsaR1Provider());
}
createProvider(keyType) {
const provider = this.providers.get(keyType);
if (!provider) {
throw createCryptoError(
"CRYPTO_PROVIDER_NOT_FOUND" /* CRYPTO_PROVIDER_NOT_FOUND */,
`No provider available for key type: ${keyType}`,
{ keyType, availableTypes: Array.from(this.providers.keys()) }
);
}
return provider;
}
supports(keyType) {
return this.providers.has(keyType);
}
};
var defaultCryptoProviderFactory = new DefaultCryptoProviderFactory();
// src/crypto/utils.ts
var CryptoUtils = class {
/**
* Generates a key pair based on the specified curve
* @param type The key type to generate (Ed25519VerificationKey2020 or EcdsaSecp256k1VerificationKey2019 or EcdsaSecp256r1VerificationKey2019)
* @returns A key pair containing public and private keys
*/
static async generateKeyPair(type = "Ed25519VerificationKey2020" /* ED25519 */) {
const keyType = typeof type === "string" ? toKeyType(type) : type;
const provider = defaultCryptoProviderFactory.createProvider(keyType);
return provider.generateKeyPair();
}
/**
* Signs data using the specified private key
* @param data The data to sign
* @param privateKey The private key to use for signing (can be Uint8Array or CryptoKey)
* @param type The key type (Ed25519VerificationKey2020 or EcdsaSecp256k1VerificationKey2019)
* @returns The signature as a Uint8Array
*/
static async sign(data, privateKey, type) {
const keyType = typeof type === "string" ? toKeyType(type) : type;
const provider = defaultCryptoProviderFactory.createProvider(keyType);
return provider.sign(data, privateKey);
}
/**
* Verifies a signature using the specified public key
* @param data The original data
* @param signature The signature to verify
* @param publicKey The public key to use for verification (can be Uint8Array or JsonWebKey)
* @param type The key type (Ed25519VerificationKey2020 or EcdsaSecp256k1VerificationKey2019)
* @returns Whether the signature is valid
*/
static async verify(data, signature, publicKey, type) {
const keyType = typeof type === "string" ? toKeyType(type) : type;
const provider = defaultCryptoProviderFactory.createProvider(keyType);
return provider.verify(data, signature, publicKey);
}
/**
* Derive public key from private key
* @param privateKey The private key bytes
* @param keyType The key type
* @returns The corresponding public key bytes
*/
static async derivePublicKey(privateKey, keyType) {
const type = typeof keyType === "string" ? toKeyType(keyType) : keyType;
const provider = defaultCryptoProviderFactory.createProvider(type);
return provider.derivePublicKey(privateKey);
}
/**
* Validate the consistency between a private key and public key pair
* @param privateKey The private key bytes
* @param publicKey The public key bytes
* @param keyType The key type
* @returns true if the keys are consistent, false otherwise
*/
static async validateKeyPairConsistency(privateKey, publicKey, keyType) {
try {
const derivedPublicKey = await this.derivePublicKey(privateKey, keyType);
return this.areUint8ArraysEqual(derivedPublicKey, publicKey);
} catch (error) {
console.warn("Key pair consistency validation failed:", error);
return false;
}
}
/**
* Compare two Uint8Array for equality
* @param a First array
* @param b Second array
* @returns true if arrays are equal, false otherwise
*/
static areUint8ArraysEqual(a, b) {
if (a.length !== b.length) return false;
for (let i = 0; i < a.length; i++) {
if (a[i] !== b[i]) return false;
}
return true;
}
};
// src/crypto/EcdsaR1PublicKey.ts
var import_p2562 = require("@noble/curves/p256");
var import_rooch_sdk = require("@roochnetwork/rooch-sdk");
var PUBLIC_KEY_SIZE = 33;
var EcdsaR1PublicKey = class extends import_rooch_sdk.PublicKey {
/**
* Create a new EcdsaR1PublicKey object
* @param value ECDSA R1 public key as buffer or base-64 encoded string
*/
constructor(value) {
super();
if (typeof value === "string") {
this.data = (0, import_rooch_sdk.fromB64)(value);
} else if (value instanceof Uint8Array) {
this.data = value;
} else {
this.data = Uint8Array.from(value);
}
if (this.data.length !== PUBLIC_KEY_SIZE) {
throw createValidationError(
"INVALID_INPUT_FORMAT" /* INVALID_INPUT_FORMAT */,
`Invalid public key input. Expected ${PUBLIC_KEY_SIZE} bytes, got ${this.data.length}`,
{ expectedSize: PUBLIC_KEY_SIZE, actualSize: this.data.length, keyType: "ECDSA-R1" }
);
}
}
/**
* Checks if two EcdsaR1 public keys are equal
*/
equals(publicKey) {
return super.equals(publicKey);
}
/**
* Return the byte array representation of the ECDSA R1 public key
*/
toBytes() {
return this.data;
}
/**
* Return the signature scheme flag for ECDSA R1
*/
flag() {
return import_rooch_sdk.SIGNATURE_SCHEME_TO_FLAG.EcdsaR1;
}
/**
* Verifies that the signature is valid for the provided message
*/
async verify(message, signature) {
try {
return import_p2562.p256.verify(signature, message, this.toBytes());
} catch (error) {
return false;
}
}
/**
* Return the Rooch address associated with this ECDSA R1 public key
*/
toAddress() {
const tmp = new Uint8Array(PUBLIC_KEY_SIZE + 1);
tmp.set([import_rooch_sdk.SIGNATURE_SCHEME_TO_FLAG.EcdsaR1]);
tmp.set(this.toBytes(), 1);
const ROOCH_ADDRESS_LENGTH = 32;
return new import_rooch_sdk.RoochAddress((0, import_rooch_sdk.blake2b)(tmp, { dkLen: 32 }).slice(0, ROOCH_ADDRESS_LENGTH * 2));
}
};
EcdsaR1PublicKey.SIZE = PUBLIC_KEY_SIZE;
// src/signers/keyStoreUtils.ts
async function signWithKeyStore(keyStore, data, keyId) {
if (typeof keyStore.sign === "function") {
return keyStore.sign(keyId, data);
}
const key = await keyStore.load(keyId);
if (!key) {
throw createKeyManagementError("KEY_NOT_FOUND" /* KEY_NOT_FOUND */, `Key not found: ${keyId}`, {
keyId
});
}
if (!key.privateKeyMultibase) {
throw createKeyManagementError(
"KEY_PRIVATE_KEY_NOT_AVAILABLE" /* KEY_PRIVATE_KEY_NOT_AVAILABLE */,
`No private key available for ${keyId}`,
{ keyId }
);
}
const privateKeyBytes = MultibaseCodec.decode(key.privateKeyMultibase);
return CryptoUtils.sign(data, privateKeyBytes, key.keyType);
}
async function canSignWithKeyStore(keyStore, keyId) {
if (typeof keyStore.sign === "function") {
const keyExists = await keyStore.load(keyId);
return keyExists !== null;
}
const key = await keyStore.load(keyId);
return !!(key && key.privateKeyMultibase);
}
async function getKeyInfoFromKeyStore(keyStore, keyId) {
const key = await keyStore.load(keyId);
if (!key) return void 0;
const publicKeyBytes = MultibaseCodec.decode(key.publicKeyMultibase);
return { type: key.keyType, publicKey: publicKeyBytes };
}
// src/signers/types.ts
function isSignerInterface(obj) {
return obj && typeof obj === "object" && typeof obj.listKeyIds === "function" && typeof obj.signWithKeyId === "function" && typeof obj.canSignWithKeyId === "function" && typeof obj.getDid === "function" && typeof obj.getKeyInfo === "function" && // Check that it's NOT a Signer (which has different methods)
typeof obj.sign !== "function";
}
// src/signers/didAccountSigner.ts
var import_rooch_sdk2 = require("@roochnetwork/rooch-sdk");
// 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