UNPKG

@sphereon/ssi-sdk.ebsi-support

Version:

118 lines (112 loc) 4.27 kB
import fetch from 'cross-fetch' import { DIDDocument } from 'did-resolver' import { wait } from '../../functions' import { logger } from '../../index' import { ApiOpts } from '../../types/IEbsiSupport' import { ebsiGetRegistryAPIUrls } from '../functions' import { GetDidDocumentParams, GetDidDocumentsParams, GetDidDocumentsResponse } from '../types' /** * Gets the DID document corresponding to the DID. * @param {{ params: GetDidDocumentParams, apiOpts?: ApiOpts }} args * @returns a did document */ export const ebsiGetDidDocument = async (args: { params: GetDidDocumentParams; apiOpts?: ApiOpts }): Promise<DIDDocument> => { const { params, apiOpts } = args const { did, validAt } = params if (!did) { throw new Error('did parameter is required') } const query = validAt ? `?valid_at=${validAt}` : '' const response = await fetch(`${ebsiGetRegistryAPIUrls({ ...apiOpts }).query}/${did}${query}`) const textBody = await response.text() const json = textBody.startsWith('{') ? JSON.parse(textBody) : undefined if (response.status >= 300 || !json) { return Promise.reject(new Error(json ?? textBody)) } return json } /** * Wait up to the number of MS for a DID Document or Verification methods and relationships to be registered. This is needed, as the EBSI blockchain does not directly propagate across all nodes, since it needs to mine for consensus first * @param args */ export const ebsiWaitTillDocumentAnchored = async ( args: GetDidDocumentParams & ApiOpts & { startIntervalMS?: number minIntervalMS?: number decreaseIntervalMSPerStep?: number maxWaitTime?: number searchForObject?: Record<string, any> }, ): Promise<{ totalWaitTime: number count: number didDocument: DIDDocument | undefined }> => { const { did, startIntervalMS = 2000, minIntervalMS = 500, decreaseIntervalMSPerStep = 250, maxWaitTime = 60_000, version = 'v5', environment = 'pilot', searchForObject, } = args if (startIntervalMS < minIntervalMS) { return Promise.reject(Error(`min interval ${minIntervalMS} needs to be smaller or equal to the start interval ${startIntervalMS}`)) } else if (decreaseIntervalMSPerStep < 0) { return Promise.reject(Error(`decrease interval per step ${decreaseIntervalMSPerStep} needs to be bigger than zero`)) } let interval = startIntervalMS let totalWaitTime = 0 let didDocument: DIDDocument | undefined let count = 0 function logCalback() { logger.debug(`Get DID Document; count ${count}: wait time: ${totalWaitTime}, ${did}`) } while (!didDocument && totalWaitTime <= maxWaitTime) { ++count try { logCalback() didDocument = await ebsiGetDidDocument({ params: { did }, apiOpts: { environment, version } }) if (searchForObject!! && didDocument) { const didDocAsStr = JSON.stringify(didDocument) const search = JSON.stringify(searchForObject) const found = didDocAsStr.includes(search.substring(1, search.length - 1)) if (!found) { logger.debug(`We did not find VM relationship or key ${JSON.stringify(searchForObject)} in DID document ${did}`) didDocument = undefined } } } catch (e) {} if (!didDocument) { await wait(interval) totalWaitTime += interval interval = Math.max(interval - decreaseIntervalMSPerStep, minIntervalMS) } } logCalback() return { didDocument, totalWaitTime, count } } /** * listDidDocuments - Returns a list of identifiers. * @param {{ params: GetDidDocumentsParams; apiOpts?: ApiOpts }} args * @returns a list of identifiers */ export const ebsiListDidDocuments = async (args: { params: GetDidDocumentsParams; apiOpts?: ApiOpts }): Promise<GetDidDocumentsResponse> => { const { params, apiOpts } = args const { offset, size, controller } = params const queryParams: string[] = [] if (offset) { queryParams.push(`page[after]=${offset}`) } if (size) { queryParams.push(`page[size]=${size}`) } if (controller) { queryParams.push(`controller=${controller}`) } const query = `?${queryParams.filter(Boolean).join('&')}` return await (await fetch(`${ebsiGetRegistryAPIUrls({ ...apiOpts }).query}/${query}`)).json() }