@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
JavaScript
/// <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