UNPKG

@dossierhq/core

Version:

The core Dossier library used by clients and server alike, used to interact with schema and entities directly, as well as remotely through a client.

175 lines 5.62 kB
/// <reference types="./ErrorResult.d.ts" /> export const ErrorType = { /** Corresponds to 400 Bad Request */ BadRequest: 'BadRequest', /** Corresponds to 409 Conflict */ Conflict: 'Conflict', /** Corresponds to 401 Unauthenticated */ NotAuthenticated: 'NotAuthenticated', /** Corresponds to 403 Forbidden */ NotAuthorized: 'NotAuthorized', /** Corresponds to 404 Not Found */ NotFound: 'NotFound', Generic: 'Generic', }; export class OkResult { value; constructor(value) { this.value = value; } isOk() { return true; } isError() { return false; } toError() { return new Error('Expected error, but was ok'); } throwIfError() { // do nothing } valueOrThrow() { return this.value; } map(mapper) { return ok(mapper(this.value)); } } export class ErrorResult { error; message; constructor(error, message) { this.error = error; this.message = message; } isOk() { return false; } isError() { return true; } toError() { return new ErrorResultError(this); } throwIfError() { throw new ErrorResultError(this); } valueOrThrow() { throw new ErrorResultError(this); } isErrorType(errorType) { return this.error === errorType; } get httpStatus() { switch (this.error) { case ErrorType.BadRequest: return 400; case ErrorType.NotAuthenticated: return 401; case ErrorType.NotAuthorized: return 403; case ErrorType.NotFound: return 404; case ErrorType.Conflict: return 409; case ErrorType.Generic: return 500; default: this.error; return 500; } } } export class ErrorResultError extends Error { errorType; errorMessage; constructor(result) { super(`${result.error}: ${result.message}`); this.name = 'ErrorResultError'; this.errorType = result.error; this.errorMessage = result.message; } } export function createErrorResult(error, message) { return new ErrorResult(error, message); } export function createErrorResultFromError(context, error, expectedErrorTypes = null) { // For some reason instanceof ErrorResultError doesn't always work, due to Next.js compilation? if (error instanceof ErrorResultError || (error instanceof Error && error.constructor.name === 'ErrorResultError')) { const e = error; const errorResult = new ErrorResult(e.errorType, e.errorMessage); if (!expectedErrorTypes || expectedErrorTypes.includes(e.errorType)) { return errorResult; } return notOk.GenericUnexpectedError(errorResult); } return notOk.GenericUnexpectedException(context, error); } export function ok(value) { return new OkResult(value); } export const notOk = { fromHttpStatus: (status, message) => { let errorType; if (status === 400) { errorType = ErrorType.BadRequest; } else if (status === 401) { errorType = ErrorType.NotAuthenticated; } else if (status === 403) { errorType = ErrorType.NotAuthorized; } else if (status === 404) { errorType = ErrorType.NotFound; } else if (status === 409) { errorType = ErrorType.Conflict; } else { errorType = ErrorType.Generic; } return createErrorResult(errorType, message); }, BadRequest: (message) => createErrorResult(ErrorType.BadRequest, message), Conflict: (message) => createErrorResult(ErrorType.Conflict, message), Generic: (message) => createErrorResult(ErrorType.Generic, message), GenericUnexpectedError: (result) => createErrorResult(ErrorType.Generic, `Unexpected error: ${result.error}: ${result.message}`), GenericUnexpectedException: (context, error) => { if (error instanceof Error) { context.logger.error('Unexpected error', error); return createErrorResult(ErrorType.Generic, `Unexpected exception: ${error.name}: ${error.message}`); } return createErrorResult(ErrorType.Generic, `Unexpected exception: ${error}`); }, NotAuthenticated: (message) => createErrorResult(ErrorType.NotAuthenticated, message), NotAuthorized: (message) => createErrorResult(ErrorType.NotAuthorized, message), NotFound: (message) => createErrorResult(ErrorType.NotFound, message), }; // ASSERTIONS class AssertionError extends Error { actual; expected; constructor(actual, expected, message) { super(message); this.name = 'AssertionError'; this.actual = actual; this.expected = expected; } } export function assertOkResult(actual) { if (actual.isError()) { throw new AssertionError(actual, undefined, `Expected ok, got error ${actual.error}: ${actual.message}`); } } export function assertErrorResultType(actual, expectedErrorType) { if (!actual.isError()) { throw new AssertionError('ok', expectedErrorType, `Expected error, but was ok`); } if (actual.error !== expectedErrorType) { throw new AssertionError(actual.error, expectedErrorType, `Expected error type ${expectedErrorType} but was ${actual.error} (message: ${actual.message})`); } } //# sourceMappingURL=ErrorResult.js.map