huge refactor to remove depenencie hell and add typesafe container

This commit is contained in:
Boki 2025-06-24 09:37:51 -04:00
parent 28b9822d55
commit 843a7b9b9b
148 changed files with 3603 additions and 2378 deletions

View file

@ -0,0 +1,14 @@
/**
* Handler Registry Package
* Provides centralized handler registration without circular dependencies
*/
export { HandlerRegistry } from './registry';
export type {
HandlerMetadata,
OperationMetadata,
ScheduleMetadata,
HandlerConfiguration,
RegistryStats,
HandlerDiscoveryResult,
} from './types';

View file

@ -0,0 +1,226 @@
/**
* Handler Registry Implementation
* Manages handler metadata and configuration without circular dependencies
*/
import type { JobHandler, ScheduledJob } from '@stock-bot/types';
import type {
HandlerConfiguration,
HandlerMetadata,
OperationMetadata,
RegistryStats,
ScheduleMetadata,
} from './types';
export class HandlerRegistry {
private handlers = new Map<string, HandlerMetadata>();
private configurations = new Map<string, HandlerConfiguration>();
private handlerServices = new Map<string, string>();
/**
* Register handler metadata
*/
registerMetadata(metadata: HandlerMetadata): void {
this.handlers.set(metadata.name, metadata);
if (metadata.service) {
this.handlerServices.set(metadata.name, metadata.service);
}
}
/**
* Register handler configuration with operation implementations
*/
registerConfiguration(config: HandlerConfiguration): void {
this.configurations.set(config.name, config);
}
/**
* Register both metadata and configuration
*/
register(metadata: HandlerMetadata, config: HandlerConfiguration): void {
this.registerMetadata(metadata);
this.registerConfiguration(config);
}
/**
* Get handler metadata
*/
getMetadata(handlerName: string): HandlerMetadata | undefined {
return this.handlers.get(handlerName);
}
/**
* Get handler configuration
*/
getConfiguration(handlerName: string): HandlerConfiguration | undefined {
return this.configurations.get(handlerName);
}
/**
* Get a specific operation handler
*/
getOperation(handlerName: string, operationName: string): JobHandler | undefined {
const config = this.configurations.get(handlerName);
return config?.operations[operationName];
}
/**
* Get all handler metadata
*/
getAllMetadata(): Map<string, HandlerMetadata> {
return new Map(this.handlers);
}
/**
* Get all handler names
*/
getHandlerNames(): string[] {
return Array.from(this.handlers.keys());
}
/**
* Check if a handler is registered
*/
hasHandler(handlerName: string): boolean {
return this.handlers.has(handlerName);
}
/**
* Get handlers for a specific service
*/
getServiceHandlers(serviceName: string): HandlerMetadata[] {
const handlers: HandlerMetadata[] = [];
for (const [handlerName, service] of this.handlerServices) {
if (service === serviceName) {
const metadata = this.handlers.get(handlerName);
if (metadata) {
handlers.push(metadata);
}
}
}
return handlers;
}
/**
* Set service ownership for a handler
*/
setHandlerService(handlerName: string, serviceName: string): void {
this.handlerServices.set(handlerName, serviceName);
// Update metadata if it exists
const metadata = this.handlers.get(handlerName);
if (metadata) {
metadata.service = serviceName;
}
}
/**
* Get the service that owns a handler
*/
getHandlerService(handlerName: string): string | undefined {
return this.handlerServices.get(handlerName);
}
/**
* Get scheduled jobs for a handler
*/
getScheduledJobs(handlerName: string): ScheduledJob[] {
const config = this.configurations.get(handlerName);
return config?.scheduledJobs || [];
}
/**
* Get all handlers with their scheduled jobs
*/
getAllHandlersWithSchedule(): Map<
string,
{ metadata: HandlerMetadata; scheduledJobs: ScheduledJob[] }
> {
const result = new Map<string, { metadata: HandlerMetadata; scheduledJobs: ScheduledJob[] }>();
for (const [name, metadata] of this.handlers) {
const config = this.configurations.get(name);
result.set(name, {
metadata,
scheduledJobs: config?.scheduledJobs || [],
});
}
return result;
}
/**
* Get registry statistics
*/
getStats(): RegistryStats {
let operationCount = 0;
let scheduledJobCount = 0;
const services = new Set<string>();
for (const metadata of this.handlers.values()) {
operationCount += metadata.operations.length;
scheduledJobCount += metadata.schedules?.length || 0;
if (metadata.service) {
services.add(metadata.service);
}
}
return {
handlers: this.handlers.size,
operations: operationCount,
scheduledJobs: scheduledJobCount,
services: services.size,
};
}
/**
* Clear all registrations (useful for testing)
*/
clear(): void {
this.handlers.clear();
this.configurations.clear();
this.handlerServices.clear();
}
/**
* Export registry data for debugging or persistence
*/
export(): {
handlers: Array<[string, HandlerMetadata]>;
configurations: Array<[string, HandlerConfiguration]>;
services: Array<[string, string]>;
} {
return {
handlers: Array.from(this.handlers.entries()),
configurations: Array.from(this.configurations.entries()),
services: Array.from(this.handlerServices.entries()),
};
}
/**
* Import registry data
*/
import(data: {
handlers: Array<[string, HandlerMetadata]>;
configurations: Array<[string, HandlerConfiguration]>;
services: Array<[string, string]>;
}): void {
this.clear();
for (const [name, metadata] of data.handlers) {
this.handlers.set(name, metadata);
}
for (const [name, config] of data.configurations) {
this.configurations.set(name, config);
}
for (const [handler, service] of data.services) {
this.handlerServices.set(handler, service);
}
}
}

View file

@ -0,0 +1,66 @@
/**
* Handler Registry Types
* Pure types for handler metadata and registration
*/
import type { JobHandler, ScheduledJob } from '@stock-bot/types';
/**
* Metadata for a single operation within a handler
*/
export interface OperationMetadata {
name: string;
method: string;
description?: string;
}
/**
* Metadata for a scheduled operation
*/
export interface ScheduleMetadata {
operation: string;
cronPattern: string;
priority?: number;
immediately?: boolean;
description?: string;
}
/**
* Complete metadata for a handler
*/
export interface HandlerMetadata {
name: string;
service?: string;
operations: OperationMetadata[];
schedules?: ScheduleMetadata[];
version?: string;
description?: string;
}
/**
* Handler configuration with operation implementations
*/
export interface HandlerConfiguration {
name: string;
operations: Record<string, JobHandler>;
scheduledJobs?: ScheduledJob[];
}
/**
* Registry statistics
*/
export interface RegistryStats {
handlers: number;
operations: number;
scheduledJobs: number;
services: number;
}
/**
* Handler discovery result
*/
export interface HandlerDiscoveryResult {
handler: HandlerMetadata;
constructor: any;
filePath?: string;
}