{"version":3,"file":"DidResolverService.mjs","names":[],"sources":["../../../../src/modules/dids/services/DidResolverService.ts"],"sourcesContent":["import type { AgentContext } from '../../../agent'\nimport { InjectionSymbols } from '../../../constants'\nimport { CredoError } from '../../../error'\nimport type { Logger } from '../../../logger'\nimport { inject, injectable } from '../../../plugins'\nimport { JsonTransformer } from '../../../utils'\nimport { CacheModuleConfig } from '../../cache'\nimport { DidsModuleConfig } from '../DidsModuleConfig'\nimport { DidDocument } from '../domain'\nimport type { DidResolver } from '../domain/DidResolver'\nimport { parseDid } from '../domain/parse'\nimport { DidRepository } from '../repository'\nimport type { DidResolutionOptions, DidResolutionResult, ParsedDid } from '../types'\n\n@injectable()\nexport class DidResolverService {\n  private logger: Logger\n  private didsModuleConfig: DidsModuleConfig\n  private didRepository: DidRepository\n\n  public constructor(\n    @inject(InjectionSymbols.Logger) logger: Logger,\n    didsModuleConfig: DidsModuleConfig,\n    didRepository: DidRepository\n  ) {\n    this.logger = logger\n    this.didsModuleConfig = didsModuleConfig\n    this.didRepository = didRepository\n  }\n\n  public async resolve(\n    agentContext: AgentContext,\n    didUrl: string,\n    options: DidResolutionOptions = {}\n  ): Promise<DidResolutionResult> {\n    this.logger.debug(`resolving didUrl ${didUrl}`)\n\n    const result = {\n      didResolutionMetadata: {},\n      didDocument: null,\n      didDocumentMetadata: {},\n    }\n\n    let parsed: ParsedDid\n    try {\n      parsed = parseDid(didUrl)\n    } catch (_error) {\n      return {\n        ...result,\n        didResolutionMetadata: { error: 'invalidDid' },\n      }\n    }\n\n    const resolver = this.findResolver(parsed)\n    if (!resolver) {\n      return {\n        ...result,\n        didResolutionMetadata: {\n          error: 'unsupportedDidMethod',\n          message: `No did resolver registered for did method ${parsed.method}`,\n        },\n      }\n    }\n\n    // extract caching options and set defaults\n    const {\n      useCache = true,\n      cacheDurationInSeconds = 300,\n      persistInCache = true,\n      useLocalCreatedDidRecord = true,\n    } = options\n    const { cacheKey, cacheScope } = this.getCacheKeyAndScope(parsed)\n\n    if (resolver.allowsCaching && useCache) {\n      const cache = agentContext.dependencyManager.resolve(CacheModuleConfig).cache\n      const cachedDidDocument = await cache.get<DidResolutionResult & { didDocument: Record<string, unknown> }>(\n        agentContext,\n        cacheKey,\n        { scope: cacheScope }\n      )\n\n      if (cachedDidDocument) {\n        return {\n          ...cachedDidDocument,\n          didDocument: JsonTransformer.fromJSON(cachedDidDocument.didDocument, DidDocument),\n          didResolutionMetadata: {\n            ...cachedDidDocument.didResolutionMetadata,\n            servedFromCache: true,\n          },\n        }\n      }\n    }\n\n    // TODO: we should store the document for future reference\n    if (resolver.allowsLocalDidRecord && useLocalCreatedDidRecord) {\n      // TODO: did should have tag whether a did document is present in the did record\n      const [didRecord] = await this.didRepository.getCreatedDids(agentContext, {\n        did: parsed.did,\n      })\n\n      if (didRecord?.didDocument) {\n        return {\n          didDocument: didRecord.didDocument,\n          didDocumentMetadata: {},\n          didResolutionMetadata: {\n            servedFromCache: false,\n            servedFromDidRecord: true,\n          },\n        }\n      }\n    }\n\n    let resolutionResult = await resolver.resolve(agentContext, parsed.did, parsed, options)\n    // Avoid overwriting existing document\n    resolutionResult = {\n      ...resolutionResult,\n      didResolutionMetadata: {\n        ...resolutionResult.didResolutionMetadata,\n        resolutionTime: Date.now(),\n        // Did resolver implementation might use did method specific caching strategy\n        // We only set to false if not defined by the resolver\n        servedFromCache: resolutionResult.didResolutionMetadata.servedFromCache ?? false,\n      },\n    }\n\n    if (resolutionResult.didDocument && resolver.allowsCaching && persistInCache) {\n      const cache = agentContext.dependencyManager.resolve(CacheModuleConfig).cache\n      await cache.set(\n        agentContext,\n        cacheKey,\n        {\n          ...resolutionResult,\n          didDocument: resolutionResult.didDocument.toJSON(),\n        },\n        // Set cache duration\n        cacheDurationInSeconds,\n        { scope: cacheScope }\n      )\n    }\n\n    return resolutionResult\n  }\n\n  /**\n   * Resolve a did document. This uses the default resolution options, and thus\n   * will use caching if available.\n   */\n  public async resolveDidDocument(agentContext: AgentContext, did: string) {\n    const {\n      didDocument,\n      didResolutionMetadata: { error, message },\n    } = await this.resolve(agentContext, did)\n\n    if (!didDocument) {\n      throw new CredoError(`Unable to resolve did document for did '${did}': ${error} ${message}`)\n    }\n    return didDocument\n  }\n\n  public async invalidateCacheForDid(agentContext: AgentContext, did: string) {\n    const cache = agentContext.dependencyManager.resolve(CacheModuleConfig).cache\n\n    let parsed: ParsedDid\n    try {\n      parsed = parseDid(did)\n    } catch (_error) {\n      // If the did is invalid, there is no cache to invalidate, so we can just return\n      return\n    }\n\n    const { cacheKey, cacheScope } = this.getCacheKeyAndScope(parsed)\n    await cache.remove(agentContext, cacheKey, { scope: cacheScope })\n  }\n\n  private getCacheKeyAndScope(parsed: ParsedDid): { cacheKey: string; cacheScope: 'context' | 'global' } {\n    return {\n      cacheKey: `did:resolver:${parsed.did}`,\n      cacheScope: this.didsModuleConfig.publicDidMethods.includes(parsed.method) ? 'global' : 'context',\n    }\n  }\n\n  private findResolver(parsed: ParsedDid): DidResolver | null {\n    return this.didsModuleConfig.resolvers.find((r) => r.supportedMethods.includes(parsed.method)) ?? null\n  }\n\n  /**\n   * Get all supported did methods for the did resolver.\n   */\n  public get supportedMethods() {\n    return Array.from(new Set(this.didsModuleConfig.resolvers.flatMap((r) => r.supportedMethods)))\n  }\n}\n"],"mappings":"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"}