UNPKG

@arcblock/did

Version:

Javascript lib to work with ArcBlock DID

97 lines (95 loc) 2.62 kB
import { getResolveRoute } from "./name.mjs"; //#region src/name-resolver.ts /** * DID Name Resolver * * Orchestrates name resolution across different registries (global, local). * Supports delegation chains with cycle detection and depth limiting. */ const DEFAULT_MAX_DEPTH = 10; /** * DID Name Resolver. * * Routes name resolution to the appropriate registry based on the name structure: * - Global names (single segment) → global registry * - .local names → local registry * - Delegated names (multi-segment) → resolve TLD first, then delegate */ var DIDNameResolver = class { constructor(opts = {}) { this.global = opts.global; this.local = opts.local; this.maxDepth = opts.maxDepth ?? DEFAULT_MAX_DEPTH; } /** * Resolve a name to a DID. * * @param name - The name to resolve (can be prefixed with 'did:name:') * @returns The resolved DID, or null if not found */ async resolve(name) { return (await this.resolveWithTrace(name)).result; } /** * Resolve a name with full trace for debugging. */ async resolveWithTrace(name) { if (!name || typeof name !== "string") throw new Error("Name must be a non-empty string"); const cleanName = name.replace(/^did:name:/, ""); if (!cleanName) throw new Error("Name cannot be empty after stripping prefix"); const visited = /* @__PURE__ */ new Set(); return this._resolve(cleanName, visited, [], 0); } async _resolve(name, visited, trace, depth) { if (visited.has(name)) { trace.push(`cycle_detected:${name}`); return { result: null, trace }; } if (depth >= this.maxDepth) { trace.push(`max_depth:${name}`); return { result: null, trace }; } visited.add(name); const route = getResolveRoute(name); let resolved = null; if (route.type === "local") { trace.push(`local:${name}`); if (this.local) resolved = this.local.resolve(route.name); } else if (route.type === "global") { trace.push(`global:${name}`); if (this.global) resolved = this.global.resolve(route.name); } else { trace.push(`delegated:${name}`); if (this.global) { resolved = this.global.resolve(name); if (!resolved) { const tldResult = this.global.resolve(route.tld); if (tldResult) resolved = tldResult; } } } if (!resolved) { trace.push(`not_found:${name}`); return { result: null, trace }; } if (resolved.startsWith("did:name:")) { const nextName = resolved.replace(/^did:name:/, ""); return this._resolve(nextName, visited, trace, depth + 1); } return { result: resolved, trace }; } }; //#endregion export { DIDNameResolver };