diff --git a/packages/blockfrost/src/blockfrostProvider.ts b/packages/blockfrost/src/blockfrostProvider.ts index 1bb1ec53381..10a9d3f5380 100644 --- a/packages/blockfrost/src/blockfrostProvider.ts +++ b/packages/blockfrost/src/blockfrostProvider.ts @@ -1,15 +1,58 @@ -import { CardanoProvider } from '@cardano-sdk/core'; -import { BlockFrostAPI } from '@blockfrost/blockfrost-js'; +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { CardanoProvider, ProviderError, ProviderFailure } from '@cardano-sdk/core'; +import { BlockFrostAPI, Error as BlockfrostError } from '@blockfrost/blockfrost-js'; import { Options } from '@blockfrost/blockfrost-js/lib/types'; import { BlockfrostToOgmios } from './BlockfrostToOgmios'; +const formatBlockfrostError = (error: unknown) => { + const blockfrostError = error as BlockfrostError; + if (typeof blockfrostError === 'string') { + throw new ProviderError(ProviderFailure.Unknown, error, blockfrostError); + } + if (typeof blockfrostError !== 'object') { + throw new ProviderError(ProviderFailure.Unknown, error, 'failed to parse error (response type)'); + } + const errorAsType1 = blockfrostError as { + status_code: number; + message: string; + error: string; + }; + if (errorAsType1.status_code) { + return errorAsType1; + } + const errorAsType2 = blockfrostError as { + errno: number; + message: string; + code: string; + }; + if (errorAsType2.code) { + const status_code = Number.parseInt(errorAsType2.code); + if (!status_code) { + throw new ProviderError(ProviderFailure.Unknown, error, 'failed to parse error (status code)'); + } + return { + status_code, + message: errorAsType1.message, + error: errorAsType2.errno.toString() + }; + } + throw new ProviderError(ProviderFailure.Unknown, error, 'failed to parse error (response json)'); +}; + +const toProviderError = (error: unknown) => { + const { status_code } = formatBlockfrostError(error); + if (status_code === 404) { + throw new ProviderError(ProviderFailure.NotFound); + } + throw new ProviderError(ProviderFailure.Unknown, error, `status_code: ${status_code}`); +}; + /** * Connect to the [Blockfrost service](https://docs.blockfrost.io/) * * @param {Options} options BlockFrostAPI options * @returns {CardanoProvider} CardanoProvider */ - export const blockfrostProvider = (options: Options): CardanoProvider => { const blockfrost = new BlockFrostAPI(options); @@ -116,7 +159,7 @@ export const blockfrostProvider = (options: Options): CardanoProvider => { return BlockfrostToOgmios.currentWalletProtocolParameters(response.data); }; - return { + const providerFunctions = { ledgerTip, networkInfo, stakePoolStats, @@ -125,5 +168,10 @@ export const blockfrostProvider = (options: Options): CardanoProvider => { queryTransactionsByAddresses, queryTransactionsByHashes, currentWalletProtocolParameters - }; + } as any; + + return Object.keys(providerFunctions).reduce((provider, key) => { + provider[key] = (...args: any[]) => providerFunctions[key](...args).catch(toProviderError); + return provider; + }, {} as any) as CardanoProvider; }; diff --git a/packages/core/src/Provider/errors.ts b/packages/core/src/Provider/errors.ts new file mode 100644 index 00000000000..cf8cbe3ac82 --- /dev/null +++ b/packages/core/src/Provider/errors.ts @@ -0,0 +1,12 @@ +import { CustomError } from 'ts-custom-error'; + +export enum ProviderFailure { + NotFound = 'NOT_FOUND', + Unknown = 'UNKNOWN' +} + +export class ProviderError extends CustomError { + constructor(public reason: ProviderFailure, public innerError?: unknown, public detail?: string) { + super(reason + (detail ? ` (${detail})` : '')); + } +} diff --git a/packages/core/src/Provider/index.ts b/packages/core/src/Provider/index.ts index fcb073fefcd..bfde7f83839 100644 --- a/packages/core/src/Provider/index.ts +++ b/packages/core/src/Provider/index.ts @@ -1 +1,2 @@ export * from './types'; +export * from './errors';