feat: add file storage service and update configurations
refactor: migrate to tsup for builds and update tsconfigs fix: update error handling and validation in payment service chore: update package scripts and dependencies docs: update README and env examples
This commit is contained in:
@@ -1,10 +1,17 @@
|
||||
import { AppError, DatabaseError, ErrorCode, ValidationError } from './types';
|
||||
import { ZodError } from "zod";
|
||||
import {
|
||||
AppError,
|
||||
DatabaseError,
|
||||
ErrorCode,
|
||||
ValidationError,
|
||||
ZodValidationError,
|
||||
} from "./types";
|
||||
|
||||
export const createAppError = <T>(
|
||||
code: T,
|
||||
message: string,
|
||||
details?: Record<string, unknown>,
|
||||
cause?: Error
|
||||
cause?: Error,
|
||||
): AppError<T> => ({
|
||||
code,
|
||||
message,
|
||||
@@ -15,7 +22,7 @@ export const createAppError = <T>(
|
||||
export const createValidationError = (
|
||||
field: string,
|
||||
value: unknown,
|
||||
message: string
|
||||
message: string,
|
||||
): ValidationError => ({
|
||||
code: ErrorCode.VALIDATION_ERROR,
|
||||
message,
|
||||
@@ -25,11 +32,34 @@ export const createValidationError = (
|
||||
|
||||
export const databaseError = (
|
||||
operation: string,
|
||||
cause?: Error
|
||||
cause?: Error,
|
||||
): DatabaseError =>
|
||||
createAppError(
|
||||
ErrorCode.DATABASE_ERROR,
|
||||
`Database error during ${operation}`,
|
||||
undefined,
|
||||
cause
|
||||
cause,
|
||||
);
|
||||
|
||||
export const createZodValidationError = (
|
||||
zodError: ZodError,
|
||||
context?: string,
|
||||
): ZodValidationError => {
|
||||
const issues = zodError.issues.map((issue) => ({
|
||||
path: issue.path as ReadonlyArray<string | number>,
|
||||
message: issue.message,
|
||||
code: issue.code,
|
||||
}));
|
||||
|
||||
const contextMessage = context ? ` in ${context}` : "";
|
||||
const message = `Validation failed${contextMessage}: ${zodError.issues
|
||||
.map((issue) => `${issue.path.join(".")} - ${issue.message}`)
|
||||
.join(", ")}`;
|
||||
|
||||
return {
|
||||
code: ErrorCode.ZOD_VALIDATION_ERROR,
|
||||
message,
|
||||
zodError,
|
||||
issues,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export * from './types';
|
||||
export * from './constructors';
|
||||
export * from './utils';
|
||||
export * from "./types";
|
||||
export * from "./constructors";
|
||||
export * from "./utils";
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import { ZodError } from "zod";
|
||||
|
||||
export enum ErrorCode {
|
||||
// System errors
|
||||
DATABASE_ERROR = 'DATABASE_ERROR',
|
||||
VALIDATION_ERROR = 'VALIDATION_ERROR',
|
||||
UNKNOWN_ERROR = 'UNKNOWN_ERROR',
|
||||
DATABASE_ERROR = "DATABASE_ERROR",
|
||||
VALIDATION_ERROR = "VALIDATION_ERROR",
|
||||
UNKNOWN_ERROR = "UNKNOWN_ERROR",
|
||||
ZOD_VALIDATION_ERROR = "ZOD_VALIDATION_ERROR",
|
||||
}
|
||||
|
||||
export type AppError<T> = {
|
||||
@@ -19,3 +22,14 @@ export type ValidationError = AppError<ErrorCode.VALIDATION_ERROR> & {
|
||||
};
|
||||
|
||||
export type DatabaseError = AppError<ErrorCode.DATABASE_ERROR>;
|
||||
|
||||
export interface ZodValidationError
|
||||
extends AppError<ErrorCode.ZOD_VALIDATION_ERROR> {
|
||||
readonly code: ErrorCode.ZOD_VALIDATION_ERROR;
|
||||
readonly zodError: ZodError;
|
||||
readonly issues: ReadonlyArray<{
|
||||
readonly path: ReadonlyArray<string | number>;
|
||||
readonly message: string;
|
||||
readonly code: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ResultAsync, err, ok } from 'neverthrow';
|
||||
import { AppError } from '../types';
|
||||
import { ResultAsync, err, ok } from "neverthrow";
|
||||
import { AppError } from "../types";
|
||||
|
||||
/**
|
||||
* Wraps a database operation in a Result type to handle errors gracefully
|
||||
@@ -9,7 +9,7 @@ import { AppError } from '../types';
|
||||
*/
|
||||
export const wrapDbOperation = <T, E extends AppError<unknown>>(
|
||||
operation: () => Promise<T>,
|
||||
errorFactory: (error: unknown) => E
|
||||
errorFactory: (error: unknown) => E,
|
||||
): ResultAsync<T, E> => {
|
||||
return ResultAsync.fromPromise(operation(), errorFactory);
|
||||
};
|
||||
@@ -17,9 +17,9 @@ export const wrapDbOperation = <T, E extends AppError<unknown>>(
|
||||
export const wrapDbOperationWithNull = <T, E extends AppError<unknown>>(
|
||||
operation: () => Promise<T | null>,
|
||||
notFoundError: E,
|
||||
dbErrorFactory: (error: unknown) => E
|
||||
dbErrorFactory: (error: unknown) => E,
|
||||
): ResultAsync<T, E> => {
|
||||
return ResultAsync.fromPromise(operation(), (error) =>
|
||||
dbErrorFactory(error)
|
||||
dbErrorFactory(error),
|
||||
).andThen((result) => (result === null ? err(notFoundError) : ok(result)));
|
||||
};
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
export * from './database';
|
||||
export * from './validation';
|
||||
export * from "./database";
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import { err, ok, Result } from 'neverthrow';
|
||||
import { output, ZodError, ZodObject } from 'zod';
|
||||
|
||||
export const safeParse =
|
||||
<T extends ZodObject>(schema: T) =>
|
||||
<D>(data: D): Result<output<T>, ZodError<output<T>>> => {
|
||||
const parseResult = schema.safeParse(data);
|
||||
|
||||
return parseResult.success ? ok(parseResult.data) : err(parseResult.error);
|
||||
};
|
||||
Reference in New Issue
Block a user