import { contexts as credentialsContexts } from '@digitalbazaar/credentials-context'; import jsonld from 'jsonld'; import { DidDocumentResolver } from '../../resolvers/didDocumentResolver.js'; import { CredentialValidationOptions } from '../dto/validationOptions.dto.js'; /** * Bundled well-known contexts to avoid network round-trips. * Covers the three URL variants shipped by @digitalbazaar/credentials-context. */ const BUNDLED_CONTEXTS: Map = new Map([ ...credentialsContexts, ]); /** * Creates a JSON-LD document loader for use with @digitalbazaar/vc * DataIntegrityProof verification. * * Resolution order: * 1. Bundled contexts (credentials/v1, credentials/v2, …) — no network * 2. DID URLs — resolved via the existing DidDocumentResolver * 3. All other URLs (e.g. custom credential contexts, * https://w3id.org/security/…) — delegated to jsonld's node loader * which fetches over HTTP (result is memoised by jsonld internally) */ export function createDocumentLoader( didDocumentResolver: DidDocumentResolver, opts?: CredentialValidationOptions, ) { const nodeLoader = jsonld.documentLoaders.node(); return async (url: string) => { // 1. Serve bundled contexts without any network call const bundled = BUNDLED_CONTEXTS.get(url); if (bundled !== undefined) { return { contextUrl: null, documentUrl: url, document: bundled }; } // 2. Resolve DID documents / verification-method objects if (url.startsWith('did:')) { const hashIndex = url.indexOf('#'); const did = hashIndex !== -1 ? url.substring(0, hashIndex) : url; const fragment = hashIndex !== -1 ? url.substring(hashIndex + 1) : null; const didDocument = await didDocumentResolver.resolveDid(did, opts); if (fragment) { // Return just the specific verification-method object so that // EcdsaMultikey.from() receives the key material it needs. const vm = (didDocument.verificationMethod ?? []).find( (m) => m.id === url || m.id === `#${fragment}`, ); if (!vm) { throw new Error( `Verification method "${url}" not found in DID document for "${did}".`, ); } return { contextUrl: null, documentUrl: url, document: vm }; } return { contextUrl: null, documentUrl: url, document: didDocument }; } // 3. Fall back to the jsonld node loader for everything else // (security contexts, custom credential contexts, …) return nodeLoader(url); }; }