format
This commit is contained in:
parent
d858222af7
commit
7d9044ab29
202 changed files with 10755 additions and 10972 deletions
|
|
@ -1,15 +1,15 @@
|
|||
{
|
||||
"service": {
|
||||
"name": "web-api",
|
||||
"port": 4000,
|
||||
"host": "0.0.0.0",
|
||||
"healthCheckPath": "/health",
|
||||
"metricsPath": "/metrics",
|
||||
"shutdownTimeout": 30000,
|
||||
"cors": {
|
||||
"enabled": true,
|
||||
"origin": ["http://localhost:4200", "http://localhost:3000", "http://localhost:3002"],
|
||||
"credentials": true
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
"service": {
|
||||
"name": "web-api",
|
||||
"port": 4000,
|
||||
"host": "0.0.0.0",
|
||||
"healthCheckPath": "/health",
|
||||
"metricsPath": "/metrics",
|
||||
"shutdownTimeout": 30000,
|
||||
"cors": {
|
||||
"enabled": true,
|
||||
"origin": ["http://localhost:4200", "http://localhost:3000", "http://localhost:3002"],
|
||||
"credentials": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,27 +1,27 @@
|
|||
import { PostgreSQLClient } from '@stock-bot/postgres';
|
||||
import { MongoDBClient } from '@stock-bot/mongodb';
|
||||
|
||||
let postgresClient: PostgreSQLClient | null = null;
|
||||
let mongodbClient: MongoDBClient | null = null;
|
||||
|
||||
export function setPostgreSQLClient(client: PostgreSQLClient): void {
|
||||
postgresClient = client;
|
||||
}
|
||||
|
||||
export function getPostgreSQLClient(): PostgreSQLClient {
|
||||
if (!postgresClient) {
|
||||
throw new Error('PostgreSQL client not initialized. Call setPostgreSQLClient first.');
|
||||
}
|
||||
return postgresClient;
|
||||
}
|
||||
|
||||
export function setMongoDBClient(client: MongoDBClient): void {
|
||||
mongodbClient = client;
|
||||
}
|
||||
|
||||
export function getMongoDBClient(): MongoDBClient {
|
||||
if (!mongodbClient) {
|
||||
throw new Error('MongoDB client not initialized. Call setMongoDBClient first.');
|
||||
}
|
||||
return mongodbClient;
|
||||
}
|
||||
import { MongoDBClient } from '@stock-bot/mongodb';
|
||||
import { PostgreSQLClient } from '@stock-bot/postgres';
|
||||
|
||||
let postgresClient: PostgreSQLClient | null = null;
|
||||
let mongodbClient: MongoDBClient | null = null;
|
||||
|
||||
export function setPostgreSQLClient(client: PostgreSQLClient): void {
|
||||
postgresClient = client;
|
||||
}
|
||||
|
||||
export function getPostgreSQLClient(): PostgreSQLClient {
|
||||
if (!postgresClient) {
|
||||
throw new Error('PostgreSQL client not initialized. Call setPostgreSQLClient first.');
|
||||
}
|
||||
return postgresClient;
|
||||
}
|
||||
|
||||
export function setMongoDBClient(client: MongoDBClient): void {
|
||||
mongodbClient = client;
|
||||
}
|
||||
|
||||
export function getMongoDBClient(): MongoDBClient {
|
||||
if (!mongodbClient) {
|
||||
throw new Error('MongoDB client not initialized. Call setMongoDBClient first.');
|
||||
}
|
||||
return mongodbClient;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,17 +77,20 @@ async function initializeServices() {
|
|||
// Initialize MongoDB client
|
||||
logger.debug('Connecting to MongoDB...');
|
||||
const mongoConfig = databaseConfig.mongodb;
|
||||
mongoClient = new MongoDBClient({
|
||||
uri: mongoConfig.uri,
|
||||
database: mongoConfig.database,
|
||||
host: mongoConfig.host,
|
||||
port: mongoConfig.port,
|
||||
timeouts: {
|
||||
connectTimeout: 30000,
|
||||
socketTimeout: 30000,
|
||||
serverSelectionTimeout: 5000,
|
||||
mongoClient = new MongoDBClient(
|
||||
{
|
||||
uri: mongoConfig.uri,
|
||||
database: mongoConfig.database,
|
||||
host: mongoConfig.host,
|
||||
port: mongoConfig.port,
|
||||
timeouts: {
|
||||
connectTimeout: 30000,
|
||||
socketTimeout: 30000,
|
||||
serverSelectionTimeout: 5000,
|
||||
},
|
||||
},
|
||||
}, logger);
|
||||
logger
|
||||
);
|
||||
await mongoClient.connect();
|
||||
setMongoDBClient(mongoClient);
|
||||
logger.info('MongoDB connected');
|
||||
|
|
@ -95,18 +98,21 @@ async function initializeServices() {
|
|||
// Initialize PostgreSQL client
|
||||
logger.debug('Connecting to PostgreSQL...');
|
||||
const pgConfig = databaseConfig.postgres;
|
||||
postgresClient = new PostgreSQLClient({
|
||||
host: pgConfig.host,
|
||||
port: pgConfig.port,
|
||||
database: pgConfig.database,
|
||||
username: pgConfig.user,
|
||||
password: pgConfig.password,
|
||||
poolSettings: {
|
||||
min: 2,
|
||||
max: pgConfig.poolSize || 10,
|
||||
idleTimeoutMillis: pgConfig.idleTimeout || 30000,
|
||||
postgresClient = new PostgreSQLClient(
|
||||
{
|
||||
host: pgConfig.host,
|
||||
port: pgConfig.port,
|
||||
database: pgConfig.database,
|
||||
username: pgConfig.user,
|
||||
password: pgConfig.password,
|
||||
poolSettings: {
|
||||
min: 2,
|
||||
max: pgConfig.poolSize || 10,
|
||||
idleTimeoutMillis: pgConfig.idleTimeout || 30000,
|
||||
},
|
||||
},
|
||||
}, logger);
|
||||
logger
|
||||
);
|
||||
await postgresClient.connect();
|
||||
setPostgreSQLClient(postgresClient);
|
||||
logger.info('PostgreSQL connected');
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@
|
|||
import { Hono } from 'hono';
|
||||
import { getLogger } from '@stock-bot/logger';
|
||||
import { exchangeService } from '../services/exchange.service';
|
||||
import { createSuccessResponse, handleError } from '../utils/error-handler';
|
||||
import {
|
||||
validateCreateExchange,
|
||||
validateUpdateExchange,
|
||||
validateCreateProviderMapping,
|
||||
validateUpdateExchange,
|
||||
validateUpdateProviderMapping,
|
||||
} from '../utils/validation';
|
||||
import { handleError, createSuccessResponse } from '../utils/error-handler';
|
||||
|
||||
const logger = getLogger('exchange-routes');
|
||||
export const exchangeRoutes = new Hono();
|
||||
|
|
@ -32,19 +32,19 @@ exchangeRoutes.get('/', async c => {
|
|||
exchangeRoutes.get('/:id', async c => {
|
||||
const exchangeId = c.req.param('id');
|
||||
logger.debug('Getting exchange by ID', { exchangeId });
|
||||
|
||||
|
||||
try {
|
||||
const result = await exchangeService.getExchangeById(exchangeId);
|
||||
|
||||
|
||||
if (!result) {
|
||||
logger.warn('Exchange not found', { exchangeId });
|
||||
return c.json(createSuccessResponse(null, 'Exchange not found'), 404);
|
||||
}
|
||||
|
||||
logger.info('Successfully retrieved exchange details', {
|
||||
exchangeId,
|
||||
logger.info('Successfully retrieved exchange details', {
|
||||
exchangeId,
|
||||
exchangeCode: result.exchange.code,
|
||||
mappingCount: result.provider_mappings.length
|
||||
mappingCount: result.provider_mappings.length,
|
||||
});
|
||||
return c.json(createSuccessResponse(result));
|
||||
} catch (error) {
|
||||
|
|
@ -56,25 +56,22 @@ exchangeRoutes.get('/:id', async c => {
|
|||
// Create new exchange
|
||||
exchangeRoutes.post('/', async c => {
|
||||
logger.debug('Creating new exchange');
|
||||
|
||||
|
||||
try {
|
||||
const body = await c.req.json();
|
||||
logger.debug('Received exchange creation request', { requestBody: body });
|
||||
|
||||
|
||||
const validatedData = validateCreateExchange(body);
|
||||
logger.debug('Exchange data validated successfully', { validatedData });
|
||||
|
||||
|
||||
const exchange = await exchangeService.createExchange(validatedData);
|
||||
logger.info('Exchange created successfully', {
|
||||
logger.info('Exchange created successfully', {
|
||||
exchangeId: exchange.id,
|
||||
code: exchange.code,
|
||||
name: exchange.name
|
||||
name: exchange.name,
|
||||
});
|
||||
|
||||
return c.json(
|
||||
createSuccessResponse(exchange, 'Exchange created successfully'),
|
||||
201
|
||||
);
|
||||
|
||||
return c.json(createSuccessResponse(exchange, 'Exchange created successfully'), 201);
|
||||
} catch (error) {
|
||||
logger.error('Failed to create exchange', { error });
|
||||
return handleError(c, error, 'to create exchange');
|
||||
|
|
@ -85,32 +82,32 @@ exchangeRoutes.post('/', async c => {
|
|||
exchangeRoutes.patch('/:id', async c => {
|
||||
const exchangeId = c.req.param('id');
|
||||
logger.debug('Updating exchange', { exchangeId });
|
||||
|
||||
|
||||
try {
|
||||
const body = await c.req.json();
|
||||
logger.debug('Received exchange update request', { exchangeId, updates: body });
|
||||
|
||||
|
||||
const validatedUpdates = validateUpdateExchange(body);
|
||||
logger.debug('Exchange update data validated', { exchangeId, validatedUpdates });
|
||||
|
||||
|
||||
const exchange = await exchangeService.updateExchange(exchangeId, validatedUpdates);
|
||||
|
||||
|
||||
if (!exchange) {
|
||||
logger.warn('Exchange not found for update', { exchangeId });
|
||||
return c.json(createSuccessResponse(null, 'Exchange not found'), 404);
|
||||
}
|
||||
|
||||
logger.info('Exchange updated successfully', {
|
||||
logger.info('Exchange updated successfully', {
|
||||
exchangeId,
|
||||
code: exchange.code,
|
||||
updates: validatedUpdates
|
||||
updates: validatedUpdates,
|
||||
});
|
||||
|
||||
|
||||
// Log special actions
|
||||
if (validatedUpdates.visible === false) {
|
||||
logger.warn('Exchange marked as hidden - provider mappings will be deleted', {
|
||||
logger.warn('Exchange marked as hidden - provider mappings will be deleted', {
|
||||
exchangeId,
|
||||
code: exchange.code
|
||||
code: exchange.code,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -124,7 +121,7 @@ exchangeRoutes.patch('/:id', async c => {
|
|||
// Get all provider mappings
|
||||
exchangeRoutes.get('/provider-mappings/all', async c => {
|
||||
logger.debug('Getting all provider mappings');
|
||||
|
||||
|
||||
try {
|
||||
const mappings = await exchangeService.getAllProviderMappings();
|
||||
logger.info('Successfully retrieved all provider mappings', { count: mappings.length });
|
||||
|
|
@ -139,18 +136,12 @@ exchangeRoutes.get('/provider-mappings/all', async c => {
|
|||
exchangeRoutes.get('/provider-mappings/:provider', async c => {
|
||||
const provider = c.req.param('provider');
|
||||
logger.debug('Getting provider mappings by provider', { provider });
|
||||
|
||||
|
||||
try {
|
||||
const mappings = await exchangeService.getProviderMappingsByProvider(provider);
|
||||
logger.info('Successfully retrieved provider mappings', { provider, count: mappings.length });
|
||||
|
||||
return c.json(
|
||||
createSuccessResponse(
|
||||
mappings,
|
||||
undefined,
|
||||
mappings.length
|
||||
)
|
||||
);
|
||||
|
||||
return c.json(createSuccessResponse(mappings, undefined, mappings.length));
|
||||
} catch (error) {
|
||||
logger.error('Failed to get provider mappings', { error, provider });
|
||||
return handleError(c, error, 'to get provider mappings');
|
||||
|
|
@ -161,26 +152,26 @@ exchangeRoutes.get('/provider-mappings/:provider', async c => {
|
|||
exchangeRoutes.patch('/provider-mappings/:id', async c => {
|
||||
const mappingId = c.req.param('id');
|
||||
logger.debug('Updating provider mapping', { mappingId });
|
||||
|
||||
|
||||
try {
|
||||
const body = await c.req.json();
|
||||
logger.debug('Received provider mapping update request', { mappingId, updates: body });
|
||||
|
||||
|
||||
const validatedUpdates = validateUpdateProviderMapping(body);
|
||||
logger.debug('Provider mapping update data validated', { mappingId, validatedUpdates });
|
||||
|
||||
|
||||
const mapping = await exchangeService.updateProviderMapping(mappingId, validatedUpdates);
|
||||
|
||||
|
||||
if (!mapping) {
|
||||
logger.warn('Provider mapping not found for update', { mappingId });
|
||||
return c.json(createSuccessResponse(null, 'Provider mapping not found'), 404);
|
||||
}
|
||||
|
||||
logger.info('Provider mapping updated successfully', {
|
||||
logger.info('Provider mapping updated successfully', {
|
||||
mappingId,
|
||||
provider: mapping.provider,
|
||||
providerExchangeCode: mapping.provider_exchange_code,
|
||||
updates: validatedUpdates
|
||||
updates: validatedUpdates,
|
||||
});
|
||||
|
||||
return c.json(createSuccessResponse(mapping, 'Provider mapping updated successfully'));
|
||||
|
|
@ -193,26 +184,23 @@ exchangeRoutes.patch('/provider-mappings/:id', async c => {
|
|||
// Create new provider mapping
|
||||
exchangeRoutes.post('/provider-mappings', async c => {
|
||||
logger.debug('Creating new provider mapping');
|
||||
|
||||
|
||||
try {
|
||||
const body = await c.req.json();
|
||||
logger.debug('Received provider mapping creation request', { requestBody: body });
|
||||
|
||||
|
||||
const validatedData = validateCreateProviderMapping(body);
|
||||
logger.debug('Provider mapping data validated successfully', { validatedData });
|
||||
|
||||
|
||||
const mapping = await exchangeService.createProviderMapping(validatedData);
|
||||
logger.info('Provider mapping created successfully', {
|
||||
logger.info('Provider mapping created successfully', {
|
||||
mappingId: mapping.id,
|
||||
provider: mapping.provider,
|
||||
providerExchangeCode: mapping.provider_exchange_code,
|
||||
masterExchangeId: mapping.master_exchange_id
|
||||
masterExchangeId: mapping.master_exchange_id,
|
||||
});
|
||||
|
||||
return c.json(
|
||||
createSuccessResponse(mapping, 'Provider mapping created successfully'),
|
||||
201
|
||||
);
|
||||
|
||||
return c.json(createSuccessResponse(mapping, 'Provider mapping created successfully'), 201);
|
||||
} catch (error) {
|
||||
logger.error('Failed to create provider mapping', { error });
|
||||
return handleError(c, error, 'to create provider mapping');
|
||||
|
|
@ -222,7 +210,7 @@ exchangeRoutes.post('/provider-mappings', async c => {
|
|||
// Get all available providers
|
||||
exchangeRoutes.get('/providers/list', async c => {
|
||||
logger.debug('Getting providers list');
|
||||
|
||||
|
||||
try {
|
||||
const providers = await exchangeService.getProviders();
|
||||
logger.info('Successfully retrieved providers list', { count: providers.length, providers });
|
||||
|
|
@ -237,21 +225,15 @@ exchangeRoutes.get('/providers/list', async c => {
|
|||
exchangeRoutes.get('/provider-exchanges/unmapped/:provider', async c => {
|
||||
const provider = c.req.param('provider');
|
||||
logger.debug('Getting unmapped provider exchanges', { provider });
|
||||
|
||||
|
||||
try {
|
||||
const exchanges = await exchangeService.getUnmappedProviderExchanges(provider);
|
||||
logger.info('Successfully retrieved unmapped provider exchanges', {
|
||||
provider,
|
||||
count: exchanges.length
|
||||
logger.info('Successfully retrieved unmapped provider exchanges', {
|
||||
provider,
|
||||
count: exchanges.length,
|
||||
});
|
||||
|
||||
return c.json(
|
||||
createSuccessResponse(
|
||||
exchanges,
|
||||
undefined,
|
||||
exchanges.length
|
||||
)
|
||||
);
|
||||
|
||||
return c.json(createSuccessResponse(exchanges, undefined, exchanges.length));
|
||||
} catch (error) {
|
||||
logger.error('Failed to get unmapped provider exchanges', { error, provider });
|
||||
return handleError(c, error, 'to get unmapped provider exchanges');
|
||||
|
|
@ -261,7 +243,7 @@ exchangeRoutes.get('/provider-exchanges/unmapped/:provider', async c => {
|
|||
// Get exchange statistics
|
||||
exchangeRoutes.get('/stats/summary', async c => {
|
||||
logger.debug('Getting exchange statistics');
|
||||
|
||||
|
||||
try {
|
||||
const stats = await exchangeService.getExchangeStats();
|
||||
logger.info('Successfully retrieved exchange statistics', { stats });
|
||||
|
|
@ -270,4 +252,4 @@ exchangeRoutes.get('/stats/summary', async c => {
|
|||
logger.error('Failed to get exchange statistics', { error });
|
||||
return handleError(c, error, 'to get exchange statistics');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
*/
|
||||
import { Hono } from 'hono';
|
||||
import { getLogger } from '@stock-bot/logger';
|
||||
import { getPostgreSQLClient, getMongoDBClient } from '../clients';
|
||||
import { getMongoDBClient, getPostgreSQLClient } from '../clients';
|
||||
|
||||
const logger = getLogger('health-routes');
|
||||
export const healthRoutes = new Hono();
|
||||
|
|
@ -11,13 +11,13 @@ export const healthRoutes = new Hono();
|
|||
// Basic health check
|
||||
healthRoutes.get('/', c => {
|
||||
logger.debug('Basic health check requested');
|
||||
|
||||
|
||||
const response = {
|
||||
status: 'healthy',
|
||||
service: 'web-api',
|
||||
timestamp: new Date().toISOString(),
|
||||
};
|
||||
|
||||
|
||||
logger.info('Basic health check successful', { status: response.status });
|
||||
return c.json(response);
|
||||
});
|
||||
|
|
@ -25,7 +25,7 @@ healthRoutes.get('/', c => {
|
|||
// Detailed health check with database connectivity
|
||||
healthRoutes.get('/detailed', async c => {
|
||||
logger.debug('Detailed health check requested');
|
||||
|
||||
|
||||
const health = {
|
||||
status: 'healthy',
|
||||
service: 'web-api',
|
||||
|
|
@ -80,19 +80,19 @@ healthRoutes.get('/detailed', async c => {
|
|||
health.status = allHealthy ? 'healthy' : 'unhealthy';
|
||||
|
||||
const statusCode = allHealthy ? 200 : 503;
|
||||
|
||||
|
||||
if (allHealthy) {
|
||||
logger.info('Detailed health check successful - all systems healthy', {
|
||||
mongodb: health.checks.mongodb.status,
|
||||
postgresql: health.checks.postgresql.status
|
||||
postgresql: health.checks.postgresql.status,
|
||||
});
|
||||
} else {
|
||||
logger.warn('Detailed health check failed - some systems unhealthy', {
|
||||
mongodb: health.checks.mongodb.status,
|
||||
postgresql: health.checks.postgresql.status,
|
||||
overallStatus: health.status
|
||||
overallStatus: health.status,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
return c.json(health, statusCode);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
import { getLogger } from '@stock-bot/logger';
|
||||
import { getPostgreSQLClient, getMongoDBClient } from '../clients';
|
||||
import { getMongoDBClient, getPostgreSQLClient } from '../clients';
|
||||
import {
|
||||
Exchange,
|
||||
ExchangeWithMappings,
|
||||
ProviderMapping,
|
||||
CreateExchangeRequest,
|
||||
UpdateExchangeRequest,
|
||||
CreateProviderMappingRequest,
|
||||
UpdateProviderMappingRequest,
|
||||
ProviderExchange,
|
||||
Exchange,
|
||||
ExchangeStats,
|
||||
ExchangeWithMappings,
|
||||
ProviderExchange,
|
||||
ProviderMapping,
|
||||
UpdateExchangeRequest,
|
||||
UpdateProviderMappingRequest,
|
||||
} from '../types/exchange.types';
|
||||
|
||||
const logger = getLogger('exchange-service');
|
||||
|
|
@ -18,7 +18,7 @@ export class ExchangeService {
|
|||
private get postgresClient() {
|
||||
return getPostgreSQLClient();
|
||||
}
|
||||
|
||||
|
||||
private get mongoClient() {
|
||||
return getMongoDBClient();
|
||||
}
|
||||
|
|
@ -63,14 +63,17 @@ export class ExchangeService {
|
|||
const mappingsResult = await this.postgresClient.query(mappingsQuery);
|
||||
|
||||
// Group mappings by exchange ID
|
||||
const mappingsByExchange = mappingsResult.rows.reduce((acc, mapping) => {
|
||||
const exchangeId = mapping.master_exchange_id;
|
||||
if (!acc[exchangeId]) {
|
||||
acc[exchangeId] = [];
|
||||
}
|
||||
acc[exchangeId].push(mapping);
|
||||
return acc;
|
||||
}, {} as Record<string, ProviderMapping[]>);
|
||||
const mappingsByExchange = mappingsResult.rows.reduce(
|
||||
(acc, mapping) => {
|
||||
const exchangeId = mapping.master_exchange_id;
|
||||
if (!acc[exchangeId]) {
|
||||
acc[exchangeId] = [];
|
||||
}
|
||||
acc[exchangeId].push(mapping);
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, ProviderMapping[]>
|
||||
);
|
||||
|
||||
// Attach mappings to exchanges
|
||||
return exchangesResult.rows.map(exchange => ({
|
||||
|
|
@ -79,7 +82,9 @@ export class ExchangeService {
|
|||
}));
|
||||
}
|
||||
|
||||
async getExchangeById(id: string): Promise<{ exchange: Exchange; provider_mappings: ProviderMapping[] } | null> {
|
||||
async getExchangeById(
|
||||
id: string
|
||||
): Promise<{ exchange: Exchange; provider_mappings: ProviderMapping[] } | null> {
|
||||
const exchangeQuery = 'SELECT * FROM exchanges WHERE id = $1 AND visible = true';
|
||||
const exchangeResult = await this.postgresClient.query(exchangeQuery, [id]);
|
||||
|
||||
|
|
@ -230,7 +235,10 @@ export class ExchangeService {
|
|||
return result.rows[0];
|
||||
}
|
||||
|
||||
async updateProviderMapping(id: string, updates: UpdateProviderMappingRequest): Promise<ProviderMapping | null> {
|
||||
async updateProviderMapping(
|
||||
id: string,
|
||||
updates: UpdateProviderMappingRequest
|
||||
): Promise<ProviderMapping | null> {
|
||||
const updateFields = [];
|
||||
const values = [];
|
||||
let paramIndex = 1;
|
||||
|
|
@ -359,7 +367,6 @@ export class ExchangeService {
|
|||
break;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
throw new Error(`Unknown provider: ${provider}`);
|
||||
}
|
||||
|
|
@ -369,4 +376,4 @@ export class ExchangeService {
|
|||
}
|
||||
|
||||
// Export singleton instance
|
||||
export const exchangeService = new ExchangeService();
|
||||
export const exchangeService = new ExchangeService();
|
||||
|
|
|
|||
|
|
@ -100,4 +100,4 @@ export interface ApiResponse<T = unknown> {
|
|||
error?: string;
|
||||
message?: string;
|
||||
total?: number;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { Context } from 'hono';
|
||||
import { getLogger } from '@stock-bot/logger';
|
||||
import { ValidationError } from './validation';
|
||||
import { ApiResponse } from '../types/exchange.types';
|
||||
import { ValidationError } from './validation';
|
||||
|
||||
const logger = getLogger('error-handler');
|
||||
|
||||
|
|
@ -61,4 +61,4 @@ export function createSuccessResponse<T>(
|
|||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
import { CreateExchangeRequest, CreateProviderMappingRequest } from '../types/exchange.types';
|
||||
|
||||
export class ValidationError extends Error {
|
||||
constructor(message: string, public field?: string) {
|
||||
constructor(
|
||||
message: string,
|
||||
public field?: string
|
||||
) {
|
||||
super(message);
|
||||
this.name = 'ValidationError';
|
||||
}
|
||||
|
|
@ -38,7 +41,10 @@ export function validateCreateExchange(data: unknown): CreateExchangeRequest {
|
|||
}
|
||||
|
||||
if (currency.length !== 3) {
|
||||
throw new ValidationError('Currency must be exactly 3 characters (e.g., USD, EUR, CAD)', 'currency');
|
||||
throw new ValidationError(
|
||||
'Currency must be exactly 3 characters (e.g., USD, EUR, CAD)',
|
||||
'currency'
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
@ -172,4 +178,4 @@ export function validateUpdateProviderMapping(data: unknown): Record<string, unk
|
|||
}
|
||||
|
||||
return updates;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue