UNPKG

@trpc/client

Version:

The tRPC client library

119 lines (105 loc) 3.53 kB
import type { inferClientTypes, InferrableClientTypes, Maybe, TRPCErrorResponse, } from '@trpc/server/unstable-core-do-not-import'; import { isObject, type DefaultErrorShape, } from '@trpc/server/unstable-core-do-not-import'; type inferErrorShape<TInferrable extends InferrableClientTypes> = inferClientTypes<TInferrable>['errorShape']; export interface TRPCClientErrorBase<TShape extends DefaultErrorShape> { readonly message: string; readonly shape: Maybe<TShape>; readonly data: Maybe<TShape['data']>; } export type TRPCClientErrorLike<TInferrable extends InferrableClientTypes> = TRPCClientErrorBase<inferErrorShape<TInferrable>>; export function isTRPCClientError<TInferrable extends InferrableClientTypes>( cause: unknown, ): cause is TRPCClientError<TInferrable> { return cause instanceof TRPCClientError; } function isTRPCErrorResponse(obj: unknown): obj is TRPCErrorResponse<any> { return ( isObject(obj) && isObject(obj['error']) && typeof obj['error']['code'] === 'number' && typeof obj['error']['message'] === 'string' ); } function getMessageFromUnknownError(err: unknown, fallback: string): string { if (typeof err === 'string') { return err; } if (isObject(err) && typeof err['message'] === 'string') { return err['message']; } return fallback; } export class TRPCClientError<TRouterOrProcedure extends InferrableClientTypes> extends Error implements TRPCClientErrorBase<inferErrorShape<TRouterOrProcedure>> { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore override doesn't work in all environments due to "This member cannot have an 'override' modifier because it is not declared in the base class 'Error'" public override readonly cause; public readonly shape: Maybe<inferErrorShape<TRouterOrProcedure>>; public readonly data: Maybe<inferErrorShape<TRouterOrProcedure>['data']>; /** * Additional meta data about the error * In the case of HTTP-errors, we'll have `response` and potentially `responseJSON` here */ public meta; constructor( message: string, opts?: { result?: Maybe<TRPCErrorResponse<inferErrorShape<TRouterOrProcedure>>>; cause?: Error; meta?: Record<string, unknown>; }, ) { const cause = opts?.cause; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore https://github.com/tc39/proposal-error-cause super(message, { cause }); this.meta = opts?.meta; this.cause = cause; this.shape = opts?.result?.error; this.data = opts?.result?.error.data; this.name = 'TRPCClientError'; Object.setPrototypeOf(this, TRPCClientError.prototype); } public static from<TRouterOrProcedure extends InferrableClientTypes>( _cause: Error | TRPCErrorResponse<any> | object, opts: { meta?: Record<string, unknown>; cause?: Error } = {}, ): TRPCClientError<TRouterOrProcedure> { const cause = _cause as unknown; if (isTRPCClientError(cause)) { if (opts.meta) { // Decorate with meta error data cause.meta = { ...cause.meta, ...opts.meta, }; } return cause; } if (isTRPCErrorResponse(cause)) { return new TRPCClientError(cause.error.message, { ...opts, result: cause, cause: opts.cause, }); } return new TRPCClientError( getMessageFromUnknownError(cause, 'Unknown error'), { ...opts, cause: cause as any, }, ); } }