fixed typescript

This commit is contained in:
Boki 2025-06-21 21:50:51 -04:00
parent 931f212ec7
commit 4096e91e67
6 changed files with 112 additions and 147 deletions

View file

@ -5,6 +5,7 @@
import type { IDataIngestionServices } from '@stock-bot/di';
import { QMHandler } from './qm/qm.handler';
import { WebShareHandler } from './webshare/webshare.handler';
/**
* Initialize and register all handlers
@ -14,10 +15,11 @@ export function initializeAllHandlers(services: IDataIngestionServices): void {
const qmHandler = new QMHandler(services);
qmHandler.register();
// TODO: Add other handlers here as they're converted
// const webShareHandler = new WebShareHandler(services);
// webShareHandler.register();
// WebShare Handler
const webShareHandler = new WebShareHandler(services);
webShareHandler.register();
// TODO: Add other handlers here as they're converted
// const ibHandler = new IBHandler(services);
// ibHandler.register();
}

View file

@ -93,13 +93,21 @@ export class QMHandler extends BaseHandler {
immediately: true,
description: 'Comprehensive symbol search using QM API'
})
async spiderSymbolSearch(payload: SymbolSpiderJob, context: ExecutionContext): Promise<unknown> {
this.logger.info('Starting QM spider symbol search', { payload });
async spiderSymbolSearch(payload: SymbolSpiderJob | undefined, context: ExecutionContext): Promise<unknown> {
// Set default payload for scheduled runs
const jobPayload: SymbolSpiderJob = payload || {
prefix: null,
depth: 1,
source: 'qm',
maxDepth: 4
};
this.logger.info('Starting QM spider symbol search', { payload: jobPayload });
// Store spider job info in cache (temporary data)
const spiderJobId = `spider:qm:${Date.now()}:${Math.random().toString(36).substr(2, 9)}`;
const spiderResult = {
payload,
payload: jobPayload,
startTime: new Date().toISOString(),
status: 'started',
jobId: spiderJobId
@ -119,18 +127,4 @@ export class QMHandler extends BaseHandler {
};
}
/**
* Provide payloads for scheduled jobs
*/
protected getScheduledJobPayload(operation: string): any {
if (operation === 'spiderSymbolSearch') {
return {
prefix: null,
depth: 1,
source: 'qm',
maxDepth: 4
};
}
return undefined;
}
}

View file

@ -1,82 +1,63 @@
/**
* WebShare Provider for proxy management with scheduled updates
*/
import { getLogger } from '@stock-bot/logger';
import type { IDataIngestionServices } from '@stock-bot/di';
import {
createJobHandler,
handlerRegistry,
type HandlerConfigWithSchedule,
} from '@stock-bot/queue';
BaseHandler,
Handler,
Operation,
QueueSchedule,
type ExecutionContext
} from '@stock-bot/handlers';
import { updateProxies } from '@stock-bot/utils';
import type { ServiceContainer } from '@stock-bot/di';
const logger = getLogger('webshare-provider');
@Handler('webshare')
export class WebShareHandler extends BaseHandler {
constructor(services: IDataIngestionServices) {
super(services);
}
// Initialize and register the WebShare provider
export function initializeWebShareProvider(_container: ServiceContainer) {
logger.debug('Registering WebShare provider with scheduled jobs...');
const webShareProviderConfig: HandlerConfigWithSchedule = {
name: 'webshare',
operations: {
'fetch-proxies': createJobHandler(async () => {
logger.info('Fetching proxies from WebShare API');
const { fetchWebShareProxies } = await import('./operations/fetch.operations');
@Operation('fetch-proxies')
@QueueSchedule('0 */6 * * *', {
priority: 3,
immediately: true,
description: 'Fetch fresh proxies from WebShare API'
})
async fetchProxies(_input: unknown, _context: ExecutionContext): Promise<unknown> {
this.logger.info('Fetching proxies from WebShare API');
try {
const { fetchWebShareProxies } = await import('./operations/fetch.operations');
const proxies = await fetchWebShareProxies();
if (proxies.length > 0) {
// Update the centralized proxy manager
await updateProxies(proxies);
try {
const proxies = await fetchWebShareProxies();
if (proxies.length > 0) {
// Update the centralized proxy manager
await updateProxies(proxies);
logger.info('Updated proxy manager with WebShare proxies', {
count: proxies.length,
workingCount: proxies.filter(p => p.isWorking !== false).length,
});
return {
success: true,
proxiesUpdated: proxies.length,
workingProxies: proxies.filter(p => p.isWorking !== false).length,
};
} else {
logger.warn('No proxies fetched from WebShare API');
return {
success: false,
proxiesUpdated: 0,
error: 'No proxies returned from API',
};
}
} catch (error) {
logger.error('Failed to fetch and update proxies', { error });
return {
success: false,
proxiesUpdated: 0,
error: error instanceof Error ? error.message : 'Unknown error',
};
}
}),
},
scheduledJobs: [
{
type: 'webshare-fetch',
operation: 'fetch-proxies',
cronPattern: '0 */6 * * *', // Every 6 hours
priority: 3,
description: 'Fetch fresh proxies from WebShare API',
immediately: true, // Run on startup
},
],
};
handlerRegistry.registerWithSchedule(webShareProviderConfig);
logger.debug('WebShare provider registered successfully');
this.logger.info('Updated proxy manager with WebShare proxies', {
count: proxies.length,
workingCount: proxies.filter(p => p.isWorking !== false).length,
});
// Cache proxy stats for monitoring
await this.cache.set('webshare-proxy-count', proxies.length, 3600);
await this.cache.set('webshare-working-count', proxies.filter(p => p.isWorking !== false).length, 3600);
await this.cache.set('last-webshare-fetch', new Date().toISOString(), 1800);
return {
success: true,
proxiesUpdated: proxies.length,
workingProxies: proxies.filter(p => p.isWorking !== false).length,
};
} else {
this.logger.warn('No proxies fetched from WebShare API');
return {
success: false,
proxiesUpdated: 0,
error: 'No proxies returned from API',
};
}
} catch (error) {
this.logger.error('Failed to fetch and update proxies', { error });
throw error;
}
}
}
export const webShareProvider = {
initialize: (container: ServiceContainer) => initializeWebShareProvider(container),
};

View file

@ -1,4 +1,4 @@
// Modern TC39 Stage 3 decorators for handler registration
// Bun-compatible decorators (hybrid approach)
/**
* Handler decorator - marks a class as a handler
@ -7,13 +7,12 @@
export function Handler(name: string) {
return function <T extends { new (...args: any[]): {} }>(
target: T,
context: ClassDecoratorContext
_context?: any
) {
// Store handler name on the constructor
(target as any).__handlerName = name;
(target as any).__needsAutoRegistration = true;
console.log('Handler decorator applied', { name, className: context.name });
return target;
};
}
@ -22,39 +21,24 @@ export function Handler(name: string) {
* Operation decorator - marks a method as an operation
* @param name Operation name
*/
export function Operation(name: string) {
export function Operation(name: string): any {
return function (
_target: Function,
context: ClassMethodDecoratorContext
) {
const methodName = String(context.name);
target: any,
methodName: string,
descriptor?: PropertyDescriptor
): any {
// Store metadata directly on the class constructor
const constructor = target.constructor;
console.log('Operation decorator applied', {
operationName: name,
methodName,
contextName: context.name,
contextKind: context.kind
if (!constructor.__operations) {
constructor.__operations = [];
}
constructor.__operations.push({
name,
method: methodName,
});
// Use context.addInitializer to run code when the class is constructed
context.addInitializer(function(this: any) {
const constructor = this.constructor as any;
if (!constructor.__operations) {
constructor.__operations = [];
}
constructor.__operations.push({
name,
method: methodName,
});
console.log('Operation registered via initializer', {
name,
methodName,
className: constructor.name
});
});
// Don't return anything - just modify metadata
return descriptor;
};
}
@ -70,27 +54,25 @@ export function QueueSchedule(
immediately?: boolean;
description?: string;
}
) {
): any {
return function (
_target: Function,
context: ClassMethodDecoratorContext
) {
const methodName = String(context.name);
target: any,
methodName: string,
descriptor?: PropertyDescriptor
): any {
// Store metadata directly on the class constructor
const constructor = target.constructor;
// Use context.addInitializer to run code when the class is constructed
context.addInitializer(function(this: any) {
const constructor = this.constructor as any;
if (!constructor.__schedules) {
constructor.__schedules = [];
}
constructor.__schedules.push({
operation: methodName,
cronPattern,
...options,
});
if (!constructor.__schedules) {
constructor.__schedules = [];
}
constructor.__schedules.push({
operation: methodName,
cronPattern,
...options,
});
// Don't return anything - just modify metadata
return descriptor;
};
}

View file

@ -6,10 +6,12 @@
"composite": true,
"incremental": true,
"types": ["bun-types"],
// Modern TC39 decorators configuration
// Modern TC39 Stage 3 decorators (TypeScript 5+ default)
"experimentalDecorators": false,
"emitDecoratorMetadata": false,
"useDefineForClassFields": true
"emitDecoratorMetadata": true,
// Suppress decorator-related type checking issues due to Bun's hybrid implementation
"skipLibCheck": true,
"suppressImplicitAnyIndexErrors": true
},
"include": ["src/**/*"],

View file

@ -37,6 +37,10 @@
"disableReferencedProjectLoad": true,
"disableSourceOfProjectReferenceRedirect": false,
// Decorator support for Bun's hybrid implementation
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
// Paths and output
"baseUrl": ".",
"paths": {