feat: implement payment service with error handling and validation
Add new payment service with repository, error handling, and validation Add exceptions package with database and validation utilities Update database package with new schema and zod types Add turbo start script for development
This commit is contained in:
17
packages/exceptions/package.json
Normal file
17
packages/exceptions/package.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "@repo/exceptions",
|
||||
"version": "0.0.0",
|
||||
"main": "./src/index.ts",
|
||||
"types": "./src/index.ts",
|
||||
"exports": {
|
||||
".": "./src/index.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"neverthrow": "^8.2.0",
|
||||
"zod": "^4.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@repo/typescript-config": "*",
|
||||
"typescript": "^5.0.0"
|
||||
}
|
||||
}
|
||||
35
packages/exceptions/src/constructors.ts
Normal file
35
packages/exceptions/src/constructors.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { AppError, DatabaseError, ErrorCode, ValidationError } from './types';
|
||||
|
||||
export const createAppError = <T>(
|
||||
code: T,
|
||||
message: string,
|
||||
details?: Record<string, unknown>,
|
||||
cause?: Error
|
||||
): AppError<T> => ({
|
||||
code,
|
||||
message,
|
||||
details,
|
||||
cause,
|
||||
});
|
||||
|
||||
export const createValidationError = (
|
||||
field: string,
|
||||
value: unknown,
|
||||
message: string
|
||||
): ValidationError => ({
|
||||
code: ErrorCode.VALIDATION_ERROR,
|
||||
message,
|
||||
field,
|
||||
value,
|
||||
});
|
||||
|
||||
export const databaseError = (
|
||||
operation: string,
|
||||
cause?: Error
|
||||
): DatabaseError =>
|
||||
createAppError(
|
||||
ErrorCode.DATABASE_ERROR,
|
||||
`Database error during ${operation}`,
|
||||
undefined,
|
||||
cause
|
||||
);
|
||||
3
packages/exceptions/src/index.ts
Normal file
3
packages/exceptions/src/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from './types';
|
||||
export * from './constructors';
|
||||
export * from './utils';
|
||||
21
packages/exceptions/src/types.ts
Normal file
21
packages/exceptions/src/types.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
export enum ErrorCode {
|
||||
// System errors
|
||||
DATABASE_ERROR = 'DATABASE_ERROR',
|
||||
VALIDATION_ERROR = 'VALIDATION_ERROR',
|
||||
UNKNOWN_ERROR = 'UNKNOWN_ERROR',
|
||||
}
|
||||
|
||||
export type AppError<T> = {
|
||||
readonly code: T;
|
||||
readonly message: string;
|
||||
readonly details?: Record<string, unknown>;
|
||||
readonly cause?: Error;
|
||||
};
|
||||
|
||||
export type ValidationError = AppError<ErrorCode.VALIDATION_ERROR> & {
|
||||
readonly code: ErrorCode.VALIDATION_ERROR;
|
||||
readonly field: string;
|
||||
readonly value: unknown;
|
||||
};
|
||||
|
||||
export type DatabaseError = AppError<ErrorCode.DATABASE_ERROR>;
|
||||
25
packages/exceptions/src/utils/database.ts
Normal file
25
packages/exceptions/src/utils/database.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { ResultAsync, err, ok } from 'neverthrow';
|
||||
import { AppError } from '../types';
|
||||
|
||||
/**
|
||||
* Wraps a database operation in a Result type to handle errors gracefully
|
||||
* @param operation - The database operation to execute
|
||||
* @param errorFactory - Function to create a custom error if the operation fails
|
||||
* @returns Result containing the operation result or error
|
||||
*/
|
||||
export const wrapDbOperation = <T, E extends AppError<unknown>>(
|
||||
operation: () => Promise<T>,
|
||||
errorFactory: (error: unknown) => E
|
||||
): ResultAsync<T, E> => {
|
||||
return ResultAsync.fromPromise(operation(), errorFactory);
|
||||
};
|
||||
|
||||
export const wrapDbOperationWithNull = <T, E extends AppError<unknown>>(
|
||||
operation: () => Promise<T | null>,
|
||||
notFoundError: E,
|
||||
dbErrorFactory: (error: unknown) => E
|
||||
): ResultAsync<T, E> => {
|
||||
return ResultAsync.fromPromise(operation(), (error) =>
|
||||
dbErrorFactory(error)
|
||||
).andThen((result) => (result === null ? err(notFoundError) : ok(result)));
|
||||
};
|
||||
2
packages/exceptions/src/utils/index.ts
Normal file
2
packages/exceptions/src/utils/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './database';
|
||||
export * from './validation';
|
||||
10
packages/exceptions/src/utils/validation.ts
Normal file
10
packages/exceptions/src/utils/validation.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
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