fixed up more type issues

This commit is contained in:
Boki 2025-06-20 09:51:32 -04:00
parent 3a10560de4
commit 87037e013f
9 changed files with 210 additions and 52 deletions

View file

@ -4,7 +4,8 @@
import { getLogger } from '@stock-bot/logger';
import type { MasterExchange } from '@stock-bot/mongodb-client';
import type { HandlerConfigWithSchedule } from '@stock-bot/queue';
import { handlerRegistry } from '@stock-bot/queue';
import { createJobHandler, handlerRegistry } from '@stock-bot/queue';
import type { IBExchange } from '../types/exchange.types';
const logger = getLogger('exchange-sync');
@ -15,16 +16,16 @@ export function initializeExchangeSyncProvider() {
name: 'exchange-sync',
operations: {
'sync-ib-exchanges': async _payload => {
'sync-ib-exchanges': createJobHandler(async () => {
logger.info('Syncing IB exchanges to master table');
return await syncIBExchanges();
},
}),
'get-master-exchange': async (payload: { masterExchangeId: string }) => {
'get-master-exchange': createJobHandler(async (payload: { masterExchangeId: string }) => {
logger.debug('Getting master exchange details', payload);
const exchange = await getMasterExchangeDetails(payload.masterExchangeId);
return { exchange, ...payload };
},
}),
},
scheduledJobs: [
@ -60,7 +61,7 @@ async function syncIBExchanges(): Promise<{ syncedCount: number; totalExchanges:
// Filter by country code US and CA
const ibExchanges = await db
.collection('ibExchanges')
.collection<IBExchange>('ibExchanges')
.find({
country_code: { $in: ['US', 'CA'] },
})
@ -99,14 +100,7 @@ async function syncIBExchanges(): Promise<{ syncedCount: number; totalExchanges:
/**
* Create or update master exchange record 1:1 from IB exchange
*/
async function createOrUpdateMasterExchange(ibExchange: {
id?: string;
name?: string;
code?: string;
country_code?: string;
currency?: string;
_id?: unknown;
}): Promise<void> {
async function createOrUpdateMasterExchange(ibExchange: IBExchange): Promise<void> {
const { connectMongoDB, getDatabase } = await import('@stock-bot/mongodb-client');
await connectMongoDB();
@ -191,11 +185,7 @@ async function getMasterExchangeDetails(masterExchangeId: string): Promise<Maste
/**
* Generate master exchange ID from IB exchange
*/
function generateMasterExchangeId(ibExchange: {
name?: string;
code?: string;
id?: string;
}): string {
function generateMasterExchangeId(ibExchange: IBExchange): string {
// Use code if available, otherwise use ID, otherwise generate from name
if (ibExchange.code) {
return ibExchange.code.toUpperCase().replace(/[^A-Z0-9]/g, '');
@ -220,7 +210,7 @@ function generateMasterExchangeId(ibExchange: {
/**
* Generate aliases for the exchange
*/
function generateAliases(ibExchange: { name?: string; code?: string }): string[] {
function generateAliases(ibExchange: IBExchange): string[] {
const aliases: string[] = [];
if (ibExchange.name && ibExchange.name.includes(' ')) {
@ -244,7 +234,7 @@ function generateAliases(ibExchange: { name?: string; code?: string }): string[]
/**
* Infer timezone from exchange name/location
*/
function inferTimezone(ibExchange: { name?: string }): string {
function inferTimezone(ibExchange: IBExchange): string {
if (!ibExchange.name) {
return 'UTC';
}

View file

@ -2,8 +2,11 @@
* Interactive Brokers Provider for new queue system
*/
import { getLogger } from '@stock-bot/logger';
import type { HandlerConfigWithSchedule } from '@stock-bot/queue';
import { handlerRegistry } from '@stock-bot/queue';
import {
createJobHandler,
handlerRegistry,
type HandlerConfigWithSchedule,
} from '@stock-bot/queue';
const logger = getLogger('ib-provider');
@ -14,14 +17,14 @@ export function initializeIBProvider() {
const ibProviderConfig: HandlerConfigWithSchedule = {
name: 'ib',
operations: {
'fetch-session': async _payload => {
'fetch-session': createJobHandler(async () => {
// payload contains session configuration (not used in current implementation)
logger.debug('Processing session fetch request');
const { fetchSession } = await import('./ib.tasks');
return fetchSession();
},
}),
'fetch-exchanges': async _payload => {
'fetch-exchanges': createJobHandler(async () => {
// payload should contain session headers
logger.debug('Processing exchanges fetch request');
const { fetchSession, fetchExchanges } = await import('./ib.tasks');
@ -30,9 +33,9 @@ export function initializeIBProvider() {
return fetchExchanges(sessionHeaders);
}
throw new Error('Failed to get session headers');
},
}),
'fetch-symbols': async _payload => {
'fetch-symbols': createJobHandler(async () => {
// payload should contain session headers
logger.debug('Processing symbols fetch request');
const { fetchSession, fetchSymbols } = await import('./ib.tasks');
@ -41,9 +44,9 @@ export function initializeIBProvider() {
return fetchSymbols(sessionHeaders);
}
throw new Error('Failed to get session headers');
},
}),
'ib-exchanges-and-symbols': async _payload => {
'ib-exchanges-and-symbols': createJobHandler(async () => {
// Legacy operation for scheduled jobs
logger.info('Fetching symbol summary from IB');
const { fetchSession, fetchExchanges, fetchSymbols } = await import('./ib.tasks');
@ -62,7 +65,8 @@ export function initializeIBProvider() {
return { exchangesCount: exchanges?.length, symbolsCount: symbols?.length };
}
},
return null;
}),
},
scheduledJobs: [
{

View file

@ -3,8 +3,7 @@
*/
import { ProxyInfo } from '@stock-bot/http';
import { getLogger } from '@stock-bot/logger';
import type { HandlerConfigWithSchedule } from '@stock-bot/queue';
import { handlerRegistry } from '@stock-bot/queue';
import { handlerRegistry, createJobHandler, type HandlerConfigWithSchedule } from '@stock-bot/queue';
const logger = getLogger('proxy-provider');
@ -16,7 +15,7 @@ export function initializeProxyProvider() {
name: 'proxy',
operations: {
'fetch-from-sources': async _payload => {
'fetch-from-sources': createJobHandler(async () => {
// Fetch proxies from all configured sources
logger.info('Processing fetch proxies from sources request');
const { fetchProxiesFromSources } = await import('./proxy.tasks');
@ -59,16 +58,16 @@ export function initializeProxyProvider() {
batchesCreated: batchResult.batchesCreated,
mode: batchResult.mode,
};
},
}),
'check-proxy': async (payload: ProxyInfo) => {
'check-proxy': createJobHandler(async (payload: ProxyInfo) => {
// payload is now the raw proxy info object
logger.debug('Processing proxy check request', {
proxy: `${payload.host}:${payload.port}`,
});
const { checkProxy } = await import('./proxy.tasks');
return checkProxy(payload);
},
}),
},
scheduledJobs: [
{

View file

@ -1,24 +1,28 @@
import { getLogger } from '@stock-bot/logger';
import { handlerRegistry, type HandlerConfigWithSchedule } from '@stock-bot/queue';
import {
handlerRegistry,
createJobHandler,
type HandlerConfigWithSchedule
} from '@stock-bot/queue';
import type { SymbolSpiderJob } from './qm.tasks';
const logger = getLogger('qm-provider');
// Initialize and register the IB provider
// Initialize and register the QM provider
export function initializeQMProvider() {
logger.debug('Registering IB provider with scheduled jobs...');
logger.debug('Registering QM provider with scheduled jobs...');
const qmProviderConfig: HandlerConfigWithSchedule = {
name: 'qm',
operations: {
'create-sessions': async () => {
'create-sessions': createJobHandler(async () => {
logger.debug('Creating QM sessions...');
const { createSessions } = await import('./qm.tasks');
await createSessions();
logger.debug('QM sessions created successfully');
return { success: true, message: 'QM sessions created successfully' };
},
'search-symbols': async () => {
}),
'search-symbols': createJobHandler(async () => {
logger.info('Starting QM symbol search...');
const { fetchSymbols } = await import('./qm.tasks');
const symbols = await fetchSymbols();
@ -39,8 +43,8 @@ export function initializeQMProvider() {
count: 0,
};
}
},
'spider-symbol-search': async (payload: SymbolSpiderJob) => {
}),
'spider-symbol-search': createJobHandler(async (payload: SymbolSpiderJob) => {
logger.debug('Processing spider symbol search job', { payload });
const { spiderSymbolSearch } = await import('./qm.tasks');
const result = await spiderSymbolSearch(payload);
@ -48,12 +52,10 @@ export function initializeQMProvider() {
logger.debug('Spider search job completed', {
success: result.success,
symbolsFound: result.symbolsFound,
jobsCreated: result.jobsCreated,
payload,
});
return result;
},
}),
},
scheduledJobs: [

View file

@ -2,8 +2,7 @@
* WebShare Provider for proxy management
*/
import { getLogger } from '@stock-bot/logger';
import type { HandlerConfigWithSchedule } from '@stock-bot/queue';
import { handlerRegistry } from '@stock-bot/queue';
import { handlerRegistry, createJobHandler, type HandlerConfigWithSchedule } from '@stock-bot/queue';
const logger = getLogger('webshare-provider');
@ -30,7 +29,7 @@ export function initializeWebShareProvider() {
name: 'webshare',
operations: {
'fetch-proxies': async _payload => {
'fetch-proxies': createJobHandler(async () => {
logger.debug('Fetching proxies from WebShare API');
try {
@ -66,7 +65,7 @@ export function initializeWebShareProvider() {
error: error instanceof Error ? error.message : 'Unknown error',
};
}
},
}),
},
scheduledJobs: [

View file

@ -0,0 +1,40 @@
/**
* Type definitions for exchange data structures
*/
export interface IBExchange {
id: string;
country_code: string;
name: string;
code?: string;
exchange_code?: string;
currency?: string;
timezone?: string;
_id?: unknown; // MongoDB ObjectId
// Add other properties as needed
}
export interface MasterExchangeData {
id: string;
code: string;
name: string;
country: string;
currency: string;
// Add other properties as needed
}
export interface QMSymbol {
symbol: string;
exchange?: string;
name?: string;
type?: string;
// Add other properties as needed
}
export interface IBSymbol {
symbol: string;
exchange: string;
name?: string;
currency?: string;
// Add other properties as needed
}

View file

@ -0,0 +1,93 @@
/**
* Type definitions for all job payloads across data service providers
*/
// Common result types
export interface JobResult {
success: boolean;
message: string;
}
export interface CountableJobResult extends JobResult {
count: number;
}
// QM Provider Types
export interface SymbolSpiderJob {
prefix: string | null; // null = root job (A-Z)
depth: number; // 1=A, 2=AA, 3=AAA, etc.
source: string; // 'qm'
maxDepth?: number; // optional max depth limit
}
export interface CreateSessionsResult extends JobResult {
// No additional fields needed
}
export interface SearchSymbolsResult extends CountableJobResult {
symbols?: unknown[]; // First 10 symbols as sample
}
export interface SpiderSymbolSearchResult extends JobResult {
symbolsFound: number;
newSymbolsAdded: number;
duplicatesSkipped: number;
errors: number;
depth: number;
prefix: string | null;
}
// IB Provider Types
export interface FetchSessionResult extends JobResult {
sessionData?: Record<string, string>;
}
export interface FetchExchangesResult extends CountableJobResult {
exchanges?: unknown[];
}
export interface FetchSymbolsResult extends CountableJobResult {
symbols?: unknown[];
}
export interface IBExchangesAndSymbolsResult extends JobResult {
exchanges: FetchExchangesResult;
symbols: FetchSymbolsResult;
}
// Proxy Provider Types
export interface ProxyInfo {
host: string;
port: number;
protocol: 'http' | 'https' | 'socks4' | 'socks5';
username?: string;
password?: string;
country?: string;
city?: string;
isValid?: boolean;
lastChecked?: Date;
}
export interface FetchProxiesFromSourcesResult extends CountableJobResult {
proxies?: ProxyInfo[];
sources: string[];
}
export interface CheckProxyResult extends JobResult {
proxy: ProxyInfo;
responseTime?: number;
error?: string;
}
// WebShare Provider Types
export interface FetchWebShareProxiesResult extends CountableJobResult {
proxies?: ProxyInfo[];
activeProxies: number;
totalQuota: number;
remainingQuota: number;
}
// No payload job types (for operations that don't need input)
export interface NoPayload {
// Empty interface for operations that don't need payload
}

View file

@ -2,6 +2,7 @@
export { Queue, type QueueWorkerConfig } from './queue';
export { QueueManager } from './queue-manager';
export { handlerRegistry } from './handler-registry';
export { createJobHandler } from './types';
// Batch processing
export { processBatchJob, processItems } from './batch-processor';
@ -34,8 +35,11 @@ export type {
// Handler types
JobHandler,
TypedJobHandler,
HandlerConfig,
TypedHandlerConfig,
HandlerConfigWithSchedule,
TypedHandlerConfigWithSchedule,
HandlerInitializer,
// Configuration types

View file

@ -104,6 +104,18 @@ export interface JobHandler<TPayload = unknown, TResult = unknown> {
(payload: TPayload): Promise<TResult>;
}
// Type-safe wrapper for creating job handlers
export type TypedJobHandler<TPayload, TResult = unknown> = (payload: TPayload) => Promise<TResult>;
// Helper to create type-safe job handlers
export function createJobHandler<TPayload = unknown, TResult = unknown>(
handler: TypedJobHandler<TPayload, TResult>
): JobHandler<unknown, TResult> {
return async (payload: unknown): Promise<TResult> => {
return handler(payload as TPayload);
};
}
export interface ScheduledJob<T = unknown> {
type: string;
operation: string;
@ -119,6 +131,11 @@ export interface HandlerConfig {
[operation: string]: JobHandler;
}
// Type-safe handler configuration
export type TypedHandlerConfig<T extends Record<string, JobHandler> = Record<string, JobHandler>> = {
[K in keyof T]: T[K];
};
export interface HandlerConfigWithSchedule {
name: string;
operations: Record<string, JobHandler>;
@ -128,6 +145,16 @@ export interface HandlerConfigWithSchedule {
operationLimits?: Record<string, RateLimitConfig>;
}
// Type-safe version of HandlerConfigWithSchedule
export interface TypedHandlerConfigWithSchedule<T extends Record<string, JobHandler> = Record<string, JobHandler>> {
name: string;
operations: T;
scheduledJobs?: ScheduledJob[];
// Rate limiting
rateLimit?: RateLimitConfig;
operationLimits?: Record<string, RateLimitConfig>;
}
export interface BatchJobData {
payloadKey: string;
batchIndex: number;