/** * @ignore */ export const ERROR_CODES = { MISSING_PARAMETER: 'missing_parameter', REMOTE_SERVICE_ERROR: 'remote_service_error', INVALID_STATE: 'invalid_state', NO_SESSION_DATA: 'no_session_data', DOES_NOT_EXIST: 'does_not_exist', FAILED_DECRYPTION_ERROR: 'failed_decryption_error', INVALID_DID_ERROR: 'invalid_did_error', NOT_ENOUGH_FUNDS_ERROR: 'not_enough_error', INVALID_AMOUNT_ERROR: 'invalid_amount_error', LOGIN_FAILED_ERROR: 'login_failed', SIGNATURE_VERIFICATION_ERROR: 'signature_verification_failure', CONFLICT_ERROR: 'conflict_error', NOT_ENOUGH_PROOF_ERROR: 'not_enough_proof_error', BAD_PATH_ERROR: 'bad_path_error', VALIDATION_ERROR: 'validation_error', PAYLOAD_TOO_LARGE_ERROR: 'payload_too_large_error', PRECONDITION_FAILED_ERROR: 'precondition_failed_error', UNKNOWN: 'unknown', }; Object.freeze(ERROR_CODES); /** * @ignore */ type ErrorData = { code: string; parameter?: string; message: string; }; /** * @ignore */ export class BlockstackError extends Error { message: string; code: string; parameter?: string; constructor(error: ErrorData) { super(); let message = error.message; let bugDetails = `Error Code: ${error.code}`; let stack = this.stack; if (!stack) { try { throw new Error(); } catch (e: any) { stack = e.stack; } } else { bugDetails += `Stack Trace:\n${stack}`; } message += `\nIf you believe this exception is caused by a bug in stacks.js, please file a bug report: https://github.com/blockstack/stacks.js/issues\n\n${bugDetails}`; this.message = message; this.code = error.code; this.parameter = error.parameter ? error.parameter : undefined; } toString() { return `${super.toString()} code: ${this.code} param: ${this.parameter ? this.parameter : 'n/a'}`; } } /** * @ignore */ export class InvalidParameterError extends BlockstackError { constructor(parameter: string, message: string = '') { super({ code: ERROR_CODES.MISSING_PARAMETER, message, parameter }); this.name = 'MissingParametersError'; } } /** * @ignore */ export class MissingParameterError extends BlockstackError { constructor(parameter: string, message: string = '') { super({ code: ERROR_CODES.MISSING_PARAMETER, message, parameter }); this.name = 'MissingParametersError'; } } /** * @ignore */ export class RemoteServiceError extends BlockstackError { response: Response; constructor(response: Response, message: string = '') { super({ code: ERROR_CODES.REMOTE_SERVICE_ERROR, message }); this.response = response; } } /** * @ignore */ export class InvalidDIDError extends BlockstackError { constructor(message: string = '') { super({ code: ERROR_CODES.INVALID_DID_ERROR, message }); this.name = 'InvalidDIDError'; } } /** * @ignore */ export class NotEnoughFundsError extends BlockstackError { leftToFund: number; constructor(leftToFund: number) { const message = `Not enough UTXOs to fund. Left to fund: ${leftToFund}`; super({ code: ERROR_CODES.NOT_ENOUGH_FUNDS_ERROR, message }); this.leftToFund = leftToFund; this.name = 'NotEnoughFundsError'; this.message = message; } } /** * @ignore */ export class InvalidAmountError extends BlockstackError { fees: number; specifiedAmount: number; constructor(fees: number, specifiedAmount: number) { const message = `Not enough coin to fund fees transaction fees. Fees would be ${fees},` + ` specified spend is ${specifiedAmount}`; super({ code: ERROR_CODES.INVALID_AMOUNT_ERROR, message }); this.specifiedAmount = specifiedAmount; this.fees = fees; this.name = 'InvalidAmountError'; this.message = message; } } /** * @ignore */ export class LoginFailedError extends BlockstackError { constructor(reason: string) { const message = `Failed to login: ${reason}`; super({ code: ERROR_CODES.LOGIN_FAILED_ERROR, message }); this.message = message; this.name = 'LoginFailedError'; } } /** * @ignore */ export class SignatureVerificationError extends BlockstackError { constructor(reason: string) { const message = `Failed to verify signature: ${reason}`; super({ code: ERROR_CODES.SIGNATURE_VERIFICATION_ERROR, message }); this.message = message; this.name = 'SignatureVerificationError'; } } /** * @ignore */ export class FailedDecryptionError extends BlockstackError { constructor(message: string = 'Unable to decrypt cipher object.') { super({ code: ERROR_CODES.FAILED_DECRYPTION_ERROR, message }); this.message = message; this.name = 'FailedDecryptionError'; } } /** * @ignore */ export class InvalidStateError extends BlockstackError { constructor(message: string) { super({ code: ERROR_CODES.INVALID_STATE, message }); this.message = message; this.name = 'InvalidStateError'; } } /** * @ignore */ export class NoSessionDataError extends BlockstackError { constructor(message: string) { super({ code: ERROR_CODES.INVALID_STATE, message }); this.message = message; this.name = 'NoSessionDataError'; } } /** * @ignore */ export interface GaiaHubErrorResponse { status: number; statusText: string; body?: any; // todo: should this be string? } export interface HubErrorDetails { message?: string; statusCode: number; statusText: string; [prop: string]: any; } /** * @ignore */ export class GaiaHubError extends BlockstackError { hubError?: HubErrorDetails; constructor(error: ErrorData, response: GaiaHubErrorResponse) { super(error); if (response) { this.hubError = { statusCode: response.status, statusText: response.statusText, }; if (typeof response.body === 'string') { this.hubError.message = response.body; } else if (typeof response.body === 'object') { Object.assign(this.hubError, response.body); } } } } /** * @ignore */ export class DoesNotExist extends GaiaHubError { constructor(message: string, response: GaiaHubErrorResponse) { super({ message, code: ERROR_CODES.DOES_NOT_EXIST }, response); this.name = 'DoesNotExist'; } } /** * @ignore */ export class ConflictError extends GaiaHubError { constructor(message: string, response: GaiaHubErrorResponse) { super({ message, code: ERROR_CODES.CONFLICT_ERROR }, response); this.name = 'ConflictError'; } } /** * @ignore */ export class NotEnoughProofError extends GaiaHubError { constructor(message: string, response: GaiaHubErrorResponse) { super({ message, code: ERROR_CODES.NOT_ENOUGH_PROOF_ERROR }, response); this.name = 'NotEnoughProofError'; } } /** * @ignore */ export class BadPathError extends GaiaHubError { constructor(message: string, response: GaiaHubErrorResponse) { super({ message, code: ERROR_CODES.BAD_PATH_ERROR }, response); this.name = 'BadPathError'; } } /** * @ignore */ export class ValidationError extends GaiaHubError { constructor(message: string, response: GaiaHubErrorResponse) { super({ message, code: ERROR_CODES.VALIDATION_ERROR }, response); this.name = 'ValidationError'; } } /** * @ignore */ export class PayloadTooLargeError extends GaiaHubError { /** Can be `null` when an oversized payload is detected client-side. */ hubError?: HubErrorDetails; maxUploadByteSize: number; constructor(message: string, response: GaiaHubErrorResponse | null, maxUploadByteSize: number) { super({ message, code: ERROR_CODES.PAYLOAD_TOO_LARGE_ERROR }, response!); this.name = 'PayloadTooLargeError'; this.maxUploadByteSize = maxUploadByteSize; } } /** * @ignore */ export class PreconditionFailedError extends GaiaHubError { constructor(message: string, response: GaiaHubErrorResponse) { super({ message, code: ERROR_CODES.PRECONDITION_FAILED_ERROR }, response); this.name = 'PreconditionFailedError'; } }