{"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 = this.getCacheKey(parsed.did)\n\n    if (resolver.allowsCaching && useCache) {\n      const cache = agentContext.dependencyManager.resolve(CacheModuleConfig).cache\n      // FIXME: in multi-tenancy it can be that the same cache is used for different agent contexts\n      // This may become a problem when resolving dids, as you can get back a cache hit for a different\n      // tenant. did:peer has disabled caching, and I think we should just recommend disabling caching\n      // for these private dids\n      // We could allow providing a custom cache prefix in the resolver options, so that the cache key\n      // can be recognized in the cache implementation\n      const cachedDidDocument = await cache.get<DidResolutionResult & { didDocument: Record<string, unknown> }>(\n        agentContext,\n        cacheKey\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      )\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    await cache.remove(agentContext, this.getCacheKey(did))\n  }\n\n  private getCacheKey(did: string) {\n    return `did:resolver:${did}`\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":";;;;;;;;;;;;;;;;;;;;;;AAeO,+BAAM,mBAAmB;CAK9B,AAAO,YACL,AAAiC,QACjC,kBACA,eACA;AACA,OAAK,SAAS;AACd,OAAK,mBAAmB;AACxB,OAAK,gBAAgB;;CAGvB,MAAa,QACX,cACA,QACA,UAAgC,EAAE,EACJ;AAC9B,OAAK,OAAO,MAAM,oBAAoB,SAAS;EAE/C,MAAM,SAAS;GACb,uBAAuB,EAAE;GACzB,aAAa;GACb,qBAAqB,EAAE;GACxB;EAED,IAAI;AACJ,MAAI;AACF,YAAS,SAAS,OAAO;WAClB,QAAQ;AACf,UAAO;IACL,GAAG;IACH,uBAAuB,EAAE,OAAO,cAAc;IAC/C;;EAGH,MAAM,WAAW,KAAK,aAAa,OAAO;AAC1C,MAAI,CAAC,SACH,QAAO;GACL,GAAG;GACH,uBAAuB;IACrB,OAAO;IACP,SAAS,6CAA6C,OAAO;IAC9D;GACF;EAIH,MAAM,EACJ,WAAW,MACX,yBAAyB,KACzB,iBAAiB,MACjB,2BAA2B,SACzB;EACJ,MAAM,WAAW,KAAK,YAAY,OAAO,IAAI;AAE7C,MAAI,SAAS,iBAAiB,UAAU;GAQtC,MAAM,oBAAoB,MAPZ,aAAa,kBAAkB,QAAQ,kBAAkB,CAAC,MAOlC,IACpC,cACA,SACD;AAED,OAAI,kBACF,QAAO;IACL,GAAG;IACH,aAAa,gBAAgB,SAAS,kBAAkB,aAAa,YAAY;IACjF,uBAAuB;KACrB,GAAG,kBAAkB;KACrB,iBAAiB;KAClB;IACF;;AAKL,MAAI,SAAS,wBAAwB,0BAA0B;GAE7D,MAAM,CAAC,aAAa,MAAM,KAAK,cAAc,eAAe,cAAc,EACxE,KAAK,OAAO,KACb,CAAC;AAEF,OAAI,WAAW,YACb,QAAO;IACL,aAAa,UAAU;IACvB,qBAAqB,EAAE;IACvB,uBAAuB;KACrB,iBAAiB;KACjB,qBAAqB;KACtB;IACF;;EAIL,IAAI,mBAAmB,MAAM,SAAS,QAAQ,cAAc,OAAO,KAAK,QAAQ,QAAQ;AAExF,qBAAmB;GACjB,GAAG;GACH,uBAAuB;IACrB,GAAG,iBAAiB;IACpB,gBAAgB,KAAK,KAAK;IAG1B,iBAAiB,iBAAiB,sBAAsB,mBAAmB;IAC5E;GACF;AAED,MAAI,iBAAiB,eAAe,SAAS,iBAAiB,eAE5D,OADc,aAAa,kBAAkB,QAAQ,kBAAkB,CAAC,MAC5D,IACV,cACA,UACA;GACE,GAAG;GACH,aAAa,iBAAiB,YAAY,QAAQ;GACnD,EAED,uBACD;AAGH,SAAO;;;;;;CAOT,MAAa,mBAAmB,cAA4B,KAAa;EACvE,MAAM,EACJ,aACA,uBAAuB,EAAE,OAAO,cAC9B,MAAM,KAAK,QAAQ,cAAc,IAAI;AAEzC,MAAI,CAAC,YACH,OAAM,IAAI,WAAW,2CAA2C,IAAI,KAAK,MAAM,GAAG,UAAU;AAE9F,SAAO;;CAGT,MAAa,sBAAsB,cAA4B,KAAa;AAE1E,QADc,aAAa,kBAAkB,QAAQ,kBAAkB,CAAC,MAC5D,OAAO,cAAc,KAAK,YAAY,IAAI,CAAC;;CAGzD,AAAQ,YAAY,KAAa;AAC/B,SAAO,gBAAgB;;CAGzB,AAAQ,aAAa,QAAuC;AAC1D,SAAO,KAAK,iBAAiB,UAAU,MAAM,MAAM,EAAE,iBAAiB,SAAS,OAAO,OAAO,CAAC,IAAI;;;;;CAMpG,IAAW,mBAAmB;AAC5B,SAAO,MAAM,KAAK,IAAI,IAAI,KAAK,iBAAiB,UAAU,SAAS,MAAM,EAAE,iBAAiB,CAAC,CAAC;;;;CAtKjG,YAAY;oBAOR,OAAO,iBAAiB,OAAO"}