wip
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
export interface AutomationEngineValidationResultDTO {
|
||||
isValid: boolean;
|
||||
error?: string;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export interface AutomationResultDTO {
|
||||
success: boolean;
|
||||
error?: string;
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { CheckoutPrice } from '../../domain/value-objects/CheckoutPrice';
|
||||
import { CheckoutState } from '../../domain/value-objects/CheckoutState';
|
||||
|
||||
export interface CheckoutConfirmationRequestDTO {
|
||||
price: CheckoutPrice;
|
||||
state: CheckoutState;
|
||||
sessionMetadata: {
|
||||
sessionName: string;
|
||||
trackId: string;
|
||||
carIds: string[];
|
||||
};
|
||||
timeoutMs: number;
|
||||
}
|
||||
8
packages/automation/application/dto/CheckoutInfoDTO.ts
Normal file
8
packages/automation/application/dto/CheckoutInfoDTO.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { CheckoutPrice } from '../../domain/value-objects/CheckoutPrice';
|
||||
import { CheckoutState } from '../../domain/value-objects/CheckoutState';
|
||||
|
||||
export interface CheckoutInfoDTO {
|
||||
price: CheckoutPrice | null;
|
||||
state: CheckoutState;
|
||||
buttonHtml: string;
|
||||
}
|
||||
5
packages/automation/application/dto/ClickResultDTO.ts
Normal file
5
packages/automation/application/dto/ClickResultDTO.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import type { AutomationResultDTO } from './AutomationResultDTO';
|
||||
|
||||
export interface ClickResultDTO extends AutomationResultDTO {
|
||||
target: string;
|
||||
}
|
||||
6
packages/automation/application/dto/FormFillResultDTO.ts
Normal file
6
packages/automation/application/dto/FormFillResultDTO.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import type { AutomationResultDTO } from './AutomationResultDTO';
|
||||
|
||||
export interface FormFillResultDTO extends AutomationResultDTO {
|
||||
fieldName: string;
|
||||
valueSet: string;
|
||||
}
|
||||
6
packages/automation/application/dto/ModalResultDTO.ts
Normal file
6
packages/automation/application/dto/ModalResultDTO.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import type { AutomationResultDTO } from './AutomationResultDTO';
|
||||
|
||||
export interface ModalResultDTO extends AutomationResultDTO {
|
||||
stepId: number;
|
||||
action: string;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import type { AutomationResultDTO } from './AutomationResultDTO';
|
||||
|
||||
export interface NavigationResultDTO extends AutomationResultDTO {
|
||||
url: string;
|
||||
loadTime: number;
|
||||
}
|
||||
11
packages/automation/application/dto/SessionDTO.ts
Normal file
11
packages/automation/application/dto/SessionDTO.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import type { HostedSessionConfig } from '../../domain/entities/HostedSessionConfig';
|
||||
|
||||
export interface SessionDTO {
|
||||
sessionId: string;
|
||||
state: string;
|
||||
currentStep: number;
|
||||
config: HostedSessionConfig;
|
||||
startedAt?: Date;
|
||||
completedAt?: Date;
|
||||
errorMessage?: string;
|
||||
}
|
||||
7
packages/automation/application/dto/WaitResultDTO.ts
Normal file
7
packages/automation/application/dto/WaitResultDTO.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import type { AutomationResultDTO } from './AutomationResultDTO';
|
||||
|
||||
export interface WaitResultDTO extends AutomationResultDTO {
|
||||
target: string;
|
||||
waitedMs: number;
|
||||
found: boolean;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { AuthenticationState } from '@gridpilot/automation/domain/value-objects/AuthenticationState';
|
||||
import { BrowserAuthenticationState } from '@gridpilot/automation/domain/value-objects/BrowserAuthenticationState';
|
||||
import { Result } from '../../shared/result/Result';
|
||||
import { AuthenticationState } from '../../domain/value-objects/AuthenticationState';
|
||||
import { BrowserAuthenticationState } from '../../domain/value-objects/BrowserAuthenticationState';
|
||||
import { Result } from '../../../shared/result/Result';
|
||||
|
||||
/**
|
||||
* Port for authentication services implementing zero-knowledge login.
|
||||
@@ -10,7 +10,7 @@ import { Result } from '../../shared/result/Result';
|
||||
* the user logs in directly with iRacing. GridPilot only observes
|
||||
* URL changes to detect successful authentication.
|
||||
*/
|
||||
export interface IAuthenticationService {
|
||||
export interface AuthenticationServicePort {
|
||||
/**
|
||||
* Check if user has a valid session without prompting login.
|
||||
* Navigates to a protected iRacing page and checks for login redirects.
|
||||
@@ -0,0 +1,9 @@
|
||||
import { HostedSessionConfig } from '../../domain/entities/HostedSessionConfig';
|
||||
import { StepId } from '../../domain/value-objects/StepId';
|
||||
import type { AutomationEngineValidationResultDTO } from '../dto/AutomationEngineValidationResultDTO';
|
||||
|
||||
export interface AutomationEnginePort {
|
||||
validateConfiguration(config: HostedSessionConfig): Promise<AutomationEngineValidationResultDTO>;
|
||||
executeStep(stepId: StepId, config: HostedSessionConfig): Promise<void>;
|
||||
stopAutomation(): void;
|
||||
}
|
||||
@@ -5,6 +5,6 @@ export type AutomationEvent = {
|
||||
payload?: any
|
||||
}
|
||||
|
||||
export interface IAutomationEventPublisher {
|
||||
export interface AutomationEventPublisherPort {
|
||||
publish(event: AutomationEvent): Promise<void>
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
export interface AutomationResult {
|
||||
success: boolean;
|
||||
error?: string;
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface NavigationResult extends AutomationResult {
|
||||
url: string;
|
||||
loadTime: number;
|
||||
}
|
||||
|
||||
export interface FormFillResult extends AutomationResult {
|
||||
fieldName: string;
|
||||
valueSet: string;
|
||||
}
|
||||
|
||||
export interface ClickResult extends AutomationResult {
|
||||
target: string;
|
||||
}
|
||||
|
||||
export interface WaitResult extends AutomationResult {
|
||||
target: string;
|
||||
waitedMs: number;
|
||||
found: boolean;
|
||||
}
|
||||
|
||||
export interface ModalResult extends AutomationResult {
|
||||
stepId: number;
|
||||
action: string;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { Result } from '../../../shared/result/Result';
|
||||
import { CheckoutConfirmation } from '../../domain/value-objects/CheckoutConfirmation';
|
||||
import type { CheckoutConfirmationRequestDTO } from '../dto/CheckoutConfirmationRequestDTO';
|
||||
|
||||
export interface CheckoutConfirmationPort {
|
||||
requestCheckoutConfirmation(
|
||||
request: CheckoutConfirmationRequestDTO
|
||||
): Promise<Result<CheckoutConfirmation>>;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import { Result } from '../../../shared/result/Result';
|
||||
import type { CheckoutInfoDTO } from '../dto/CheckoutInfoDTO';
|
||||
|
||||
export interface CheckoutServicePort {
|
||||
extractCheckoutInfo(): Promise<Result<CheckoutInfoDTO>>;
|
||||
proceedWithCheckout(): Promise<Result<void>>;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
import { HostedSessionConfig } from '@gridpilot/automation/domain/entities/HostedSessionConfig';
|
||||
import { StepId } from '@gridpilot/automation/domain/value-objects/StepId';
|
||||
|
||||
export interface ValidationResult {
|
||||
isValid: boolean;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface IAutomationEngine {
|
||||
validateConfiguration(config: HostedSessionConfig): Promise<ValidationResult>;
|
||||
executeStep(stepId: StepId, config: HostedSessionConfig): Promise<void>;
|
||||
stopAutomation(): void;
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import { Result } from '../../shared/result/Result';
|
||||
import { CheckoutConfirmation } from '@gridpilot/automation/domain/value-objects/CheckoutConfirmation';
|
||||
import { CheckoutPrice } from '@gridpilot/automation/domain/value-objects/CheckoutPrice';
|
||||
import { CheckoutState } from '@gridpilot/automation/domain/value-objects/CheckoutState';
|
||||
|
||||
export interface CheckoutConfirmationRequest {
|
||||
price: CheckoutPrice;
|
||||
state: CheckoutState;
|
||||
sessionMetadata: {
|
||||
sessionName: string;
|
||||
trackId: string;
|
||||
carIds: string[];
|
||||
};
|
||||
timeoutMs: number;
|
||||
}
|
||||
|
||||
export interface ICheckoutConfirmationPort {
|
||||
requestCheckoutConfirmation(
|
||||
request: CheckoutConfirmationRequest
|
||||
): Promise<Result<CheckoutConfirmation>>;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import { Result } from '../../shared/result/Result';
|
||||
import { CheckoutPrice } from '@gridpilot/automation/domain/value-objects/CheckoutPrice';
|
||||
import { CheckoutState } from '@gridpilot/automation/domain/value-objects/CheckoutState';
|
||||
|
||||
export interface CheckoutInfo {
|
||||
price: CheckoutPrice | null;
|
||||
state: CheckoutState;
|
||||
buttonHtml: string;
|
||||
}
|
||||
|
||||
export interface ICheckoutService {
|
||||
extractCheckoutInfo(): Promise<Result<CheckoutInfo>>;
|
||||
proceedWithCheckout(): Promise<Result<void>>;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/**
|
||||
* Log levels in order of severity (lowest to highest)
|
||||
*/
|
||||
export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal';
|
||||
|
||||
/**
|
||||
* Contextual metadata attached to log entries
|
||||
*/
|
||||
export interface LogContext {
|
||||
/** Unique session identifier for correlation */
|
||||
sessionId?: string;
|
||||
/** Current automation step (1-18) */
|
||||
stepId?: number;
|
||||
/** Step name for human readability */
|
||||
stepName?: string;
|
||||
/** Adapter or component name */
|
||||
adapter?: string;
|
||||
/** Operation duration in milliseconds */
|
||||
durationMs?: number;
|
||||
/** Additional arbitrary metadata */
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* ILogger - Port interface for application-layer logging.
|
||||
*/
|
||||
export interface ILogger {
|
||||
debug(message: string, context?: LogContext): void;
|
||||
info(message: string, context?: LogContext): void;
|
||||
warn(message: string, context?: LogContext): void;
|
||||
error(message: string, error?: Error, context?: LogContext): void;
|
||||
fatal(message: string, error?: Error, context?: LogContext): void;
|
||||
child(context: LogContext): ILogger;
|
||||
flush(): Promise<void>;
|
||||
}
|
||||
17
packages/automation/application/ports/LoggerContext.ts
Normal file
17
packages/automation/application/ports/LoggerContext.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Contextual metadata attached to log entries
|
||||
*/
|
||||
export interface LogContext {
|
||||
/** Unique session identifier for correlation */
|
||||
sessionId?: string;
|
||||
/** Current automation step (1-18) */
|
||||
stepId?: number;
|
||||
/** Step name for human readability */
|
||||
stepName?: string;
|
||||
/** Adapter or component name */
|
||||
adapter?: string;
|
||||
/** Operation duration in milliseconds */
|
||||
durationMs?: number;
|
||||
/** Additional arbitrary metadata */
|
||||
[key: string]: unknown;
|
||||
}
|
||||
4
packages/automation/application/ports/LoggerLogLevel.ts
Normal file
4
packages/automation/application/ports/LoggerLogLevel.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Log levels in order of severity (lowest to highest)
|
||||
*/
|
||||
export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal';
|
||||
15
packages/automation/application/ports/LoggerPort.ts
Normal file
15
packages/automation/application/ports/LoggerPort.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import type { LogLevel } from './LoggerLogLevel';
|
||||
import type { LogContext } from './LoggerContext';
|
||||
|
||||
/**
|
||||
* LoggerPort - Port interface for application-layer logging.
|
||||
*/
|
||||
export interface LoggerPort {
|
||||
debug(message: string, context?: LogContext): void;
|
||||
info(message: string, context?: LogContext): void;
|
||||
warn(message: string, context?: LogContext): void;
|
||||
error(message: string, error?: Error, context?: LogContext): void;
|
||||
fatal(message: string, error?: Error, context?: LogContext): void;
|
||||
child(context: LogContext): LoggerPort;
|
||||
flush(): Promise<void>;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
export type OverlayAction = { id: string; label: string; meta?: Record<string, unknown>; timeoutMs?: number }
|
||||
export type ActionAck = { id: string; status: 'confirmed' | 'tentative' | 'failed'; reason?: string }
|
||||
|
||||
export interface IOverlaySyncPort {
|
||||
export interface OverlaySyncPort {
|
||||
startAction(action: OverlayAction): Promise<ActionAck>
|
||||
cancelAction(actionId: string): Promise<void>
|
||||
}
|
||||
@@ -1,12 +1,10 @@
|
||||
import { StepId } from '@gridpilot/automation/domain/value-objects/StepId';
|
||||
import {
|
||||
NavigationResult,
|
||||
FormFillResult,
|
||||
ClickResult,
|
||||
WaitResult,
|
||||
ModalResult,
|
||||
AutomationResult,
|
||||
} from './AutomationResults';
|
||||
import { StepId } from '../../domain/value-objects/StepId';
|
||||
import type { NavigationResultDTO } from '../dto/NavigationResultDTO';
|
||||
import type { ClickResultDTO } from '../dto/ClickResultDTO';
|
||||
import type { WaitResultDTO } from '../dto/WaitResultDTO';
|
||||
import type { ModalResultDTO } from '../dto/ModalResultDTO';
|
||||
import type { AutomationResultDTO } from '../dto/AutomationResultDTO';
|
||||
import type { FormFillResultDTO } from '../dto/FormFillResultDTO';
|
||||
|
||||
/**
|
||||
* Browser automation interface for Playwright-based automation.
|
||||
@@ -19,38 +17,38 @@ export interface IBrowserAutomation {
|
||||
/**
|
||||
* Navigate to a URL.
|
||||
*/
|
||||
navigateToPage(url: string): Promise<NavigationResult>;
|
||||
navigateToPage(url: string): Promise<NavigationResultDTO>;
|
||||
|
||||
/**
|
||||
* Fill a form field by name or selector.
|
||||
*/
|
||||
fillFormField(fieldName: string, value: string): Promise<FormFillResult>;
|
||||
fillFormField(fieldName: string, value: string): Promise<FormFillResultDTO>;
|
||||
|
||||
/**
|
||||
* Click an element by selector or action name.
|
||||
*/
|
||||
clickElement(target: string): Promise<ClickResult>;
|
||||
clickElement(target: string): Promise<ClickResultDTO>;
|
||||
|
||||
/**
|
||||
* Wait for an element to appear.
|
||||
*/
|
||||
waitForElement(target: string, maxWaitMs?: number): Promise<WaitResult>;
|
||||
waitForElement(target: string, maxWaitMs?: number): Promise<WaitResultDTO>;
|
||||
|
||||
/**
|
||||
* Handle modal dialogs.
|
||||
*/
|
||||
handleModal(stepId: StepId, action: string): Promise<ModalResult>;
|
||||
handleModal(stepId: StepId, action: string): Promise<ModalResultDTO>;
|
||||
|
||||
/**
|
||||
* Execute a complete workflow step.
|
||||
*/
|
||||
executeStep?(stepId: StepId, config: Record<string, unknown>): Promise<AutomationResult>;
|
||||
executeStep?(stepId: StepId, config: Record<string, unknown>): Promise<AutomationResultDTO>;
|
||||
|
||||
/**
|
||||
* Initialize the browser connection.
|
||||
* Returns an AutomationResult indicating success or failure.
|
||||
*/
|
||||
connect?(): Promise<AutomationResult>;
|
||||
connect?(): Promise<AutomationResultDTO>;
|
||||
|
||||
/**
|
||||
* Clean up browser resources.
|
||||
@@ -62,9 +60,3 @@ export interface IBrowserAutomation {
|
||||
*/
|
||||
isConnected?(): boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use IBrowserAutomation directly. IScreenAutomation was for OS-level
|
||||
* automation which has been removed in favor of browser-only automation.
|
||||
*/
|
||||
export type IScreenAutomation = IBrowserAutomation;
|
||||
@@ -1,7 +1,7 @@
|
||||
import { AutomationSession } from '@gridpilot/automation/domain/entities/AutomationSession';
|
||||
import { SessionStateValue } from '@gridpilot/automation/domain/value-objects/SessionState';
|
||||
import { AutomationSession } from '../../domain/entities/AutomationSession';
|
||||
import { SessionStateValue } from '../../domain/value-objects/SessionState';
|
||||
|
||||
export interface ISessionRepository {
|
||||
export interface SessionRepositoryPort {
|
||||
save(session: AutomationSession): Promise<void>;
|
||||
findById(id: string): Promise<AutomationSession | null>;
|
||||
update(session: AutomationSession): Promise<void>;
|
||||
@@ -0,0 +1,5 @@
|
||||
import type { Result } from '../../../shared/result/Result';
|
||||
|
||||
export interface SessionValidatorPort {
|
||||
validateSession(): Promise<Result<boolean>>;
|
||||
}
|
||||
@@ -1,22 +1,22 @@
|
||||
import { IOverlaySyncPort, OverlayAction, ActionAck } from '../ports/IOverlaySyncPort';
|
||||
import { IAutomationEventPublisher, AutomationEvent } from '../ports/IAutomationEventPublisher';
|
||||
import { OverlaySyncPort, OverlayAction, ActionAck } from '../ports/OverlaySyncPort';
|
||||
import { AutomationEventPublisherPort, AutomationEvent } from '../ports/AutomationEventPublisherPort';
|
||||
import { IAutomationLifecycleEmitter, LifecycleCallback } from '../../infrastructure/adapters/IAutomationLifecycleEmitter';
|
||||
import { ILogger } from '../ports/ILogger';
|
||||
import { LoggerPort } from '../ports/LoggerPort';
|
||||
|
||||
type ConstructorArgs = {
|
||||
lifecycleEmitter: IAutomationLifecycleEmitter
|
||||
publisher: IAutomationEventPublisher
|
||||
logger: ILogger
|
||||
publisher: AutomationEventPublisherPort
|
||||
logger: LoggerPort
|
||||
initialPanelWaitMs?: number
|
||||
maxPanelRetries?: number
|
||||
backoffFactor?: number
|
||||
defaultTimeoutMs?: number
|
||||
}
|
||||
|
||||
export class OverlaySyncService implements IOverlaySyncPort {
|
||||
export class OverlaySyncService implements OverlaySyncPort {
|
||||
private lifecycleEmitter: IAutomationLifecycleEmitter
|
||||
private publisher: IAutomationEventPublisher
|
||||
private logger: ILogger
|
||||
private publisher: AutomationEventPublisherPort
|
||||
private logger: LoggerPort
|
||||
private initialPanelWaitMs: number
|
||||
private maxPanelRetries: number
|
||||
private backoffFactor: number
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
import { AuthenticationState } from '@gridpilot/automation/domain/value-objects/AuthenticationState';
|
||||
import { Result } from '../../shared/result/Result';
|
||||
import type { IAuthenticationService } from '../ports/IAuthenticationService';
|
||||
import { SessionLifetime } from '@gridpilot/automation/domain/value-objects/SessionLifetime';
|
||||
|
||||
/**
|
||||
* Port for optional server-side session validation.
|
||||
*/
|
||||
export interface ISessionValidator {
|
||||
validateSession(): Promise<Result<boolean>>;
|
||||
}
|
||||
import { AuthenticationState } from '../../domain/value-objects/AuthenticationState';
|
||||
import { Result } from '../../../shared/result/Result';
|
||||
import type { AuthenticationServicePort } from '../ports/AuthenticationServicePort';
|
||||
import { SessionLifetime } from '../../domain/value-objects/SessionLifetime';
|
||||
import type { SessionValidatorPort } from '../ports/SessionValidatorPort';
|
||||
|
||||
/**
|
||||
* Use case for checking if the user has a valid iRacing session.
|
||||
@@ -22,8 +16,8 @@ export interface ISessionValidator {
|
||||
*/
|
||||
export class CheckAuthenticationUseCase {
|
||||
constructor(
|
||||
private readonly authService: IAuthenticationService,
|
||||
private readonly sessionValidator?: ISessionValidator
|
||||
private readonly authService: AuthenticationServicePort,
|
||||
private readonly sessionValidator?: SessionValidatorPort
|
||||
) {}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Result } from '../../shared/result/Result';
|
||||
import type { IAuthenticationService } from '../ports/IAuthenticationService';
|
||||
import { Result } from '../../../shared/result/Result';
|
||||
import type { AuthenticationServicePort } from '../ports/AuthenticationServicePort';
|
||||
|
||||
/**
|
||||
* Use case for clearing the user's session (logout).
|
||||
@@ -8,7 +8,7 @@ import type { IAuthenticationService } from '../ports/IAuthenticationService';
|
||||
* the user out. The next automation attempt will require re-authentication.
|
||||
*/
|
||||
export class ClearSessionUseCase {
|
||||
constructor(private readonly authService: IAuthenticationService) {}
|
||||
constructor(private readonly authService: AuthenticationServicePort) {}
|
||||
|
||||
/**
|
||||
* Execute the session clearing.
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Result } from '../../shared/result/Result';
|
||||
import { RaceCreationResult } from '@gridpilot/automation/domain/value-objects/RaceCreationResult';
|
||||
import type { ICheckoutService } from '../ports/ICheckoutService';
|
||||
import { Result } from '../../../shared/result/Result';
|
||||
import { RaceCreationResult } from '../../domain/value-objects/RaceCreationResult';
|
||||
import type { CheckoutServicePort } from '../ports/CheckoutServicePort';
|
||||
|
||||
export class CompleteRaceCreationUseCase {
|
||||
constructor(private readonly checkoutService: ICheckoutService) {}
|
||||
constructor(private readonly checkoutService: CheckoutServicePort) {}
|
||||
|
||||
async execute(sessionId: string): Promise<Result<RaceCreationResult>> {
|
||||
if (!sessionId || sessionId.trim() === '') {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Result } from '../../shared/result/Result';
|
||||
import { ICheckoutService } from '../ports/ICheckoutService';
|
||||
import { ICheckoutConfirmationPort } from '../ports/ICheckoutConfirmationPort';
|
||||
import { CheckoutStateEnum } from '@gridpilot/automation/domain/value-objects/CheckoutState';
|
||||
import { Result } from '../../../shared/result/Result';
|
||||
import type { CheckoutServicePort } from '../ports/CheckoutServicePort';
|
||||
import type { CheckoutConfirmationPort } from '../ports/CheckoutConfirmationPort';
|
||||
import { CheckoutStateEnum } from '../../domain/value-objects/CheckoutState';
|
||||
|
||||
interface SessionMetadata {
|
||||
sessionName: string;
|
||||
@@ -13,8 +13,8 @@ export class ConfirmCheckoutUseCase {
|
||||
private static readonly DEFAULT_TIMEOUT_MS = 30000;
|
||||
|
||||
constructor(
|
||||
private readonly checkoutService: ICheckoutService,
|
||||
private readonly confirmationPort: ICheckoutConfirmationPort
|
||||
private readonly checkoutService: CheckoutServicePort,
|
||||
private readonly confirmationPort: CheckoutConfirmationPort
|
||||
) {}
|
||||
|
||||
async execute(sessionMetadata?: SessionMetadata): Promise<Result<void>> {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Result } from '../../shared/result/Result';
|
||||
import type { IAuthenticationService } from '../ports/IAuthenticationService';
|
||||
import { Result } from '../../../shared/result/Result';
|
||||
import type { AuthenticationServicePort } from '../ports/AuthenticationServicePort';
|
||||
|
||||
/**
|
||||
* Use case for initiating the manual login flow.
|
||||
@@ -9,7 +9,7 @@ import type { IAuthenticationService } from '../ports/IAuthenticationService';
|
||||
* indicating successful login.
|
||||
*/
|
||||
export class InitiateLoginUseCase {
|
||||
constructor(private readonly authService: IAuthenticationService) {}
|
||||
constructor(private readonly authService: AuthenticationServicePort) {}
|
||||
|
||||
/**
|
||||
* Execute the login flow.
|
||||
|
||||
@@ -1,24 +1,15 @@
|
||||
import { AutomationSession } from '@gridpilot/automation/domain/entities/AutomationSession';
|
||||
import { HostedSessionConfig } from '@gridpilot/automation/domain/entities/HostedSessionConfig';
|
||||
import { IAutomationEngine } from '../ports/IAutomationEngine';
|
||||
import type { IBrowserAutomation } from '../ports/IScreenAutomation';
|
||||
import { ISessionRepository } from '../ports/ISessionRepository';
|
||||
|
||||
export interface SessionDTO {
|
||||
sessionId: string;
|
||||
state: string;
|
||||
currentStep: number;
|
||||
config: HostedSessionConfig;
|
||||
startedAt?: Date;
|
||||
completedAt?: Date;
|
||||
errorMessage?: string;
|
||||
}
|
||||
import { AutomationSession } from '../../domain/entities/AutomationSession';
|
||||
import { HostedSessionConfig } from '../../domain/entities/HostedSessionConfig';
|
||||
import { AutomationEnginePort } from '../ports/AutomationEnginePort';
|
||||
import type { IBrowserAutomation } from '../ports/ScreenAutomationPort';
|
||||
import { SessionRepositoryPort } from '../ports/SessionRepositoryPort';
|
||||
import type { SessionDTO } from '../dto/SessionDTO';
|
||||
|
||||
export class StartAutomationSessionUseCase {
|
||||
constructor(
|
||||
private readonly automationEngine: IAutomationEngine,
|
||||
private readonly automationEngine: AutomationEnginePort,
|
||||
private readonly browserAutomation: IBrowserAutomation,
|
||||
private readonly sessionRepository: ISessionRepository
|
||||
private readonly sessionRepository: SessionRepositoryPort
|
||||
) {}
|
||||
|
||||
async execute(config: HostedSessionConfig): Promise<SessionDTO> {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { IAuthenticationService } from '../ports/IAuthenticationService';
|
||||
import { Result } from '../../shared/result/Result';
|
||||
import { BrowserAuthenticationState } from '@gridpilot/automation/domain/value-objects/BrowserAuthenticationState';
|
||||
import type { AuthenticationServicePort } from '../ports/AuthenticationServicePort';
|
||||
import { Result } from '../../../shared/result/Result';
|
||||
import { BrowserAuthenticationState } from '../../domain/value-objects/BrowserAuthenticationState';
|
||||
|
||||
/**
|
||||
* Use case for verifying browser shows authenticated page state.
|
||||
@@ -8,7 +8,7 @@ import { BrowserAuthenticationState } from '@gridpilot/automation/domain/value-o
|
||||
*/
|
||||
export class VerifyAuthenticatedPageUseCase {
|
||||
constructor(
|
||||
private readonly authService: IAuthenticationService
|
||||
private readonly authService: AuthenticationServicePort
|
||||
) {}
|
||||
|
||||
async execute(): Promise<Result<BrowserAuthenticationState>> {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Result } from '../shared/Result';
|
||||
import { Result } from '../../../shared/result/Result';
|
||||
|
||||
/**
|
||||
* Configuration for page state validation.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AutomationEvent } from '../../application/ports/IAutomationEventPublisher';
|
||||
import { AutomationEvent } from '@gridpilot/automation/application/ports/AutomationEventPublisherPort';
|
||||
|
||||
export type LifecycleCallback = (event: AutomationEvent) => Promise<void> | void;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Result } from '../../../shared/result/Result';
|
||||
import { CheckoutPrice } from '@gridpilot/automation/domain/value-objects/CheckoutPrice';
|
||||
import { CheckoutState } from '@gridpilot/automation/domain/value-objects/CheckoutState';
|
||||
import { CheckoutInfo } from '../../../application/ports/ICheckoutService';
|
||||
import { Result } from '../../../../shared/result/Result';
|
||||
import { CheckoutPrice } from '../../../domain/value-objects/CheckoutPrice';
|
||||
import { CheckoutState } from '../../../domain/value-objects/CheckoutState';
|
||||
import type { CheckoutInfoDTO } from '../../../application/dto/CheckoutInfoDTO';
|
||||
import { IRACING_SELECTORS } from './dom/IRacingSelectors';
|
||||
|
||||
interface Page {
|
||||
@@ -22,7 +22,7 @@ export class CheckoutPriceExtractor {
|
||||
|
||||
constructor(private readonly page: Page) {}
|
||||
|
||||
async extractCheckoutInfo(): Promise<Result<CheckoutInfo>> {
|
||||
async extractCheckoutInfo(): Promise<Result<CheckoutInfoDTO>> {
|
||||
try {
|
||||
// Prefer the explicit pill element which contains the price
|
||||
const pillLocator = this.page.locator('.label-pill, .label-inverse');
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Page } from 'playwright';
|
||||
import { ILogger } from '../../../../application/ports/ILogger';
|
||||
import { LoggerPort } from '@gridpilot/automation/application/ports/LoggerPort';
|
||||
|
||||
export class AuthenticationGuard {
|
||||
constructor(
|
||||
private readonly page: Page,
|
||||
private readonly logger?: ILogger
|
||||
private readonly logger?: LoggerPort
|
||||
) {}
|
||||
|
||||
async checkForLoginUI(): Promise<boolean> {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { Page } from 'playwright';
|
||||
import type { ILogger } from '../../../../application/ports/ILogger';
|
||||
import type { LoggerPort } from '@gridpilot/automation/application/ports/LoggerPort';
|
||||
import type { IPlaywrightAuthFlow } from './PlaywrightAuthFlow';
|
||||
import { IRACING_URLS, IRACING_SELECTORS, IRACING_TIMEOUTS } from '../dom/IRacingSelectors';
|
||||
import { AuthenticationGuard } from './AuthenticationGuard';
|
||||
|
||||
export class IRacingPlaywrightAuthFlow implements IPlaywrightAuthFlow {
|
||||
constructor(private readonly logger?: ILogger) {}
|
||||
constructor(private readonly logger?: LoggerPort) {}
|
||||
|
||||
getLoginUrl(): string {
|
||||
return IRACING_URLS.login;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import * as fs from 'fs';
|
||||
import type { BrowserContext, Page } from 'playwright';
|
||||
|
||||
import type { IAuthenticationService } from '../../../../application/ports/IAuthenticationService';
|
||||
import type { ILogger } from '../../../../application/ports/ILogger';
|
||||
import { AuthenticationState } from '@gridpilot/automation/domain/value-objects/AuthenticationState';
|
||||
import { BrowserAuthenticationState } from '@gridpilot/automation/domain/value-objects/BrowserAuthenticationState';
|
||||
import { Result } from '../../../../shared/result/Result';
|
||||
import type { AuthenticationServicePort } from '../../../../application/ports/AuthenticationServicePort';
|
||||
import type { LoggerPort } from '../../../../application/ports/LoggerPort';
|
||||
import { AuthenticationState } from '../../../../domain/value-objects/AuthenticationState';
|
||||
import { BrowserAuthenticationState } from '../../../../domain/value-objects/BrowserAuthenticationState';
|
||||
import { Result } from '../../../../../shared/result/Result';
|
||||
import { PlaywrightBrowserSession } from '../core/PlaywrightBrowserSession';
|
||||
import { SessionCookieStore } from './SessionCookieStore';
|
||||
import type { IPlaywrightAuthFlow } from './PlaywrightAuthFlow';
|
||||
@@ -26,11 +26,11 @@ interface PlaywrightAuthSessionConfig {
|
||||
* - Cookie persistence via SessionCookieStore
|
||||
* - Exposing the IAuthenticationService port for application layer
|
||||
*/
|
||||
export class PlaywrightAuthSessionService implements IAuthenticationService {
|
||||
export class PlaywrightAuthSessionService implements AuthenticationServicePort {
|
||||
private readonly browserSession: PlaywrightBrowserSession;
|
||||
private readonly cookieStore: SessionCookieStore;
|
||||
private readonly authFlow: IPlaywrightAuthFlow;
|
||||
private readonly logger?: ILogger;
|
||||
private readonly logger?: LoggerPort;
|
||||
|
||||
private readonly navigationTimeoutMs: number;
|
||||
private readonly loginWaitTimeoutMs: number;
|
||||
@@ -41,7 +41,7 @@ export class PlaywrightAuthSessionService implements IAuthenticationService {
|
||||
browserSession: PlaywrightBrowserSession,
|
||||
cookieStore: SessionCookieStore,
|
||||
authFlow: IPlaywrightAuthFlow,
|
||||
logger?: ILogger,
|
||||
logger?: LoggerPort,
|
||||
config?: PlaywrightAuthSessionConfig,
|
||||
) {
|
||||
this.browserSession = browserSession;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import * as fs from 'fs/promises';
|
||||
import * as path from 'path';
|
||||
import { AuthenticationState } from '@gridpilot/automation/domain/value-objects/AuthenticationState';
|
||||
import { CookieConfiguration } from '@gridpilot/automation/domain/value-objects/CookieConfiguration';
|
||||
import { Result } from '../../../../shared/result/Result';
|
||||
import type { ILogger } from '../../../../application/ports/ILogger';
|
||||
import { AuthenticationState } from '../../../../domain/value-objects/AuthenticationState';
|
||||
import { CookieConfiguration } from '../../../../domain/value-objects/CookieConfiguration';
|
||||
import { Result } from '../../../../../shared/result/Result';
|
||||
import type { LoggerPort } from '../../../../application/ports/LoggerPort';
|
||||
|
||||
interface Cookie {
|
||||
name: string;
|
||||
@@ -43,9 +43,9 @@ const EXPIRY_BUFFER_SECONDS = 300;
|
||||
|
||||
export class SessionCookieStore {
|
||||
private readonly storagePath: string;
|
||||
private logger?: ILogger;
|
||||
|
||||
constructor(userDataDir: string, logger?: ILogger) {
|
||||
private logger?: LoggerPort;
|
||||
|
||||
constructor(userDataDir: string, logger?: LoggerPort) {
|
||||
this.storagePath = path.join(userDataDir, 'session-state.json');
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@@ -1,24 +1,22 @@
|
||||
import type { Browser, Page, BrowserContext } from 'playwright';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { StepId } from '@gridpilot/automation/domain/value-objects/StepId';
|
||||
import { AuthenticationState } from '@gridpilot/automation/domain/value-objects/AuthenticationState';
|
||||
import { BrowserAuthenticationState } from '@gridpilot/automation/domain/value-objects/BrowserAuthenticationState';
|
||||
import { CheckoutPrice } from '@gridpilot/automation/domain/value-objects/CheckoutPrice';
|
||||
import { CheckoutState } from '@gridpilot/automation/domain/value-objects/CheckoutState';
|
||||
import { CheckoutConfirmation } from '@gridpilot/automation/domain/value-objects/CheckoutConfirmation';
|
||||
import type { IBrowserAutomation } from '../../../../application/ports/IScreenAutomation';
|
||||
import type {
|
||||
NavigationResult,
|
||||
FormFillResult,
|
||||
ClickResult,
|
||||
WaitResult,
|
||||
ModalResult,
|
||||
AutomationResult,
|
||||
} from '../../../../application/ports/AutomationResults';
|
||||
import type { IAuthenticationService } from '../../../../application/ports/IAuthenticationService';
|
||||
import type { ILogger } from '../../../../application/ports/ILogger';
|
||||
import { Result } from '../../../../shared/result/Result';
|
||||
import { StepId } from '../../../../domain/value-objects/StepId';
|
||||
import { AuthenticationState } from '../../../../domain/value-objects/AuthenticationState';
|
||||
import { BrowserAuthenticationState } from '../../../../domain/value-objects/BrowserAuthenticationState';
|
||||
import { CheckoutPrice } from '../../../../domain/value-objects/CheckoutPrice';
|
||||
import { CheckoutState } from '../../../../domain/value-objects/CheckoutState';
|
||||
import { CheckoutConfirmation } from '../../../../domain/value-objects/CheckoutConfirmation';
|
||||
import type { IBrowserAutomation } from '../../../../application/ports/ScreenAutomationPort';
|
||||
import type { NavigationResultDTO } from '../../../../application/dto/NavigationResultDTO';
|
||||
import type { FormFillResultDTO } from '../../../../application/dto/FormFillResultDTO';
|
||||
import type { ClickResultDTO } from '../../../../application/dto/ClickResultDTO';
|
||||
import type { WaitResultDTO } from '../../../../application/dto/WaitResultDTO';
|
||||
import type { ModalResultDTO } from '../../../../application/dto/ModalResultDTO';
|
||||
import type { AutomationResultDTO } from '../../../../application/dto/AutomationResultDTO';
|
||||
import type { AuthenticationServicePort } from '../../../../application/ports/AuthenticationServicePort';
|
||||
import type { LoggerPort } from '../../../../application/ports/LoggerPort';
|
||||
import { Result } from '../../../../../shared/result/Result';
|
||||
import { IRACING_SELECTORS, IRACING_URLS, IRACING_TIMEOUTS, ALL_BLOCKED_SELECTORS, BLOCKED_KEYWORDS } from '../dom/IRacingSelectors';
|
||||
import { SessionCookieStore } from '../auth/SessionCookieStore';
|
||||
import { PlaywrightBrowserSession } from './PlaywrightBrowserSession';
|
||||
@@ -421,7 +419,7 @@ export interface PlaywrightConfig {
|
||||
userDataDir?: string;
|
||||
}
|
||||
|
||||
export class PlaywrightAutomationAdapter implements IBrowserAutomation, IAuthenticationService {
|
||||
export class PlaywrightAutomationAdapter implements IBrowserAutomation, AuthenticationServicePort {
|
||||
private browser: Browser | null = null;
|
||||
private persistentContext: BrowserContext | null = null;
|
||||
private context: BrowserContext | null = null;
|
||||
@@ -430,7 +428,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, IAuthent
|
||||
private browserSession: PlaywrightBrowserSession;
|
||||
private connected = false;
|
||||
private isConnecting = false;
|
||||
private logger?: ILogger;
|
||||
private logger?: LoggerPort;
|
||||
private cookieStore: SessionCookieStore;
|
||||
private authService: PlaywrightAuthSessionService;
|
||||
private overlayInjected = false;
|
||||
@@ -450,7 +448,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, IAuthent
|
||||
private domInteractor!: IRacingDomInteractor;
|
||||
private readonly stepOrchestrator: WizardStepOrchestrator;
|
||||
|
||||
constructor(config: PlaywrightConfig = {}, logger?: ILogger, browserModeLoader?: BrowserModeConfigLoader) {
|
||||
constructor(config: PlaywrightConfig = {}, logger?: LoggerPort, browserModeLoader?: BrowserModeConfigLoader) {
|
||||
this.config = {
|
||||
headless: true,
|
||||
timeout: 10000,
|
||||
@@ -623,7 +621,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, IAuthent
|
||||
this.connected = this.browserSession.isConnected();
|
||||
}
|
||||
|
||||
async connect(forceHeaded: boolean = false): Promise<AutomationResult> {
|
||||
async connect(forceHeaded: boolean = false): Promise<AutomationResultDTO> {
|
||||
const result = await this.browserSession.connect(forceHeaded);
|
||||
if (!result.success) {
|
||||
return { success: false, error: result.error };
|
||||
@@ -701,7 +699,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, IAuthent
|
||||
return this.connected && this.page !== null;
|
||||
}
|
||||
|
||||
async navigateToPage(url: string): Promise<NavigationResult> {
|
||||
async navigateToPage(url: string): Promise<NavigationResultDTO> {
|
||||
const result = await this.navigator.navigateToPage(url);
|
||||
if (result.success) {
|
||||
// Reset overlay state after successful navigation (page context changed)
|
||||
@@ -710,7 +708,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, IAuthent
|
||||
return result;
|
||||
}
|
||||
|
||||
async fillFormField(fieldName: string, value: string): Promise<FormFillResult> {
|
||||
async fillFormField(fieldName: string, value: string): Promise<FormFillResultDTO> {
|
||||
return this.domInteractor.fillFormField(fieldName, value);
|
||||
}
|
||||
|
||||
@@ -727,7 +725,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, IAuthent
|
||||
return fieldMap[fieldName] || IRACING_SELECTORS.fields.textInput;
|
||||
}
|
||||
|
||||
async clickElement(target: string): Promise<ClickResult> {
|
||||
async clickElement(target: string): Promise<ClickResultDTO> {
|
||||
return this.domInteractor.clickElement(target);
|
||||
}
|
||||
|
||||
@@ -749,15 +747,15 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, IAuthent
|
||||
return actionMap[action] || `button:has-text("${action}")`;
|
||||
}
|
||||
|
||||
async waitForElement(target: string, maxWaitMs?: number): Promise<WaitResult> {
|
||||
async waitForElement(target: string, maxWaitMs?: number): Promise<WaitResultDTO> {
|
||||
return this.navigator.waitForElement(target, maxWaitMs);
|
||||
}
|
||||
|
||||
async handleModal(stepId: StepId, action: string): Promise<ModalResult> {
|
||||
async handleModal(stepId: StepId, action: string): Promise<ModalResultDTO> {
|
||||
return this.domInteractor.handleModal(stepId, action);
|
||||
}
|
||||
|
||||
async executeStep(stepId: StepId, config: Record<string, unknown>): Promise<AutomationResult> {
|
||||
async executeStep(stepId: StepId, config: Record<string, unknown>): Promise<AutomationResultDTO> {
|
||||
const stepNumber = stepId.value;
|
||||
const skipFixtureNavigation =
|
||||
(config as any).__skipFixtureNavigation === true;
|
||||
@@ -1989,7 +1987,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, IAuthent
|
||||
* First checks if user is already authenticated - if so, navigates directly to hosted sessions.
|
||||
* Otherwise navigates to login page and waits for user to complete manual login.
|
||||
*/
|
||||
private async handleLogin(): Promise<AutomationResult> {
|
||||
private async handleLogin(): Promise<AutomationResultDTO> {
|
||||
try {
|
||||
if (this.config.baseUrl && !this.config.baseUrl.includes('members.iracing.com')) {
|
||||
this.log('info', 'Fixture baseUrl detected, treating session as authenticated for Step 1', {
|
||||
@@ -2120,7 +2118,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, IAuthent
|
||||
* Tries the primary selector first, then falls back to alternative selectors.
|
||||
* This is needed because iRacing's form structure can vary slightly.
|
||||
*/
|
||||
private async fillFieldWithFallback(fieldName: string, value: string): Promise<FormFillResult> {
|
||||
private async fillFieldWithFallback(fieldName: string, value: string): Promise<FormFillResultDTO> {
|
||||
if (!this.page) {
|
||||
return { success: false, fieldName, valueSet: value, error: 'Browser not connected' };
|
||||
}
|
||||
@@ -2224,7 +2222,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, IAuthent
|
||||
}
|
||||
}
|
||||
|
||||
async clickAction(action: string): Promise<ClickResult> {
|
||||
async clickAction(action: string): Promise<ClickResultDTO> {
|
||||
if (!this.page) {
|
||||
return { success: false, target: action, error: 'Browser not connected' };
|
||||
}
|
||||
@@ -2253,7 +2251,7 @@ export class PlaywrightAutomationAdapter implements IBrowserAutomation, IAuthent
|
||||
return { success: true, target: selector };
|
||||
}
|
||||
|
||||
async fillField(fieldName: string, value: string): Promise<FormFillResult> {
|
||||
async fillField(fieldName: string, value: string): Promise<FormFillResultDTO> {
|
||||
if (!this.page) {
|
||||
return { success: false, fieldName, valueSet: value, error: 'Browser not connected' };
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import StealthPlugin from 'puppeteer-extra-plugin-stealth';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
import type { ILogger } from '../../../../application/ports/ILogger';
|
||||
import type { LoggerPort } from '@gridpilot/automation/application/ports/LoggerPort';
|
||||
import { BrowserModeConfigLoader, BrowserMode } from '../../../config/BrowserModeConfig';
|
||||
import { getAutomationMode } from '../../../config/AutomationConfig';
|
||||
import type { PlaywrightConfig } from './PlaywrightAutomationAdapter';
|
||||
@@ -27,7 +27,7 @@ export class PlaywrightBrowserSession {
|
||||
|
||||
constructor(
|
||||
private readonly config: Required<PlaywrightConfig>,
|
||||
private readonly logger?: ILogger,
|
||||
private readonly logger?: LoggerPort,
|
||||
browserModeLoader?: BrowserModeConfigLoader,
|
||||
) {
|
||||
const automationMode = getAutomationMode();
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
import type { Page } from 'playwright';
|
||||
import { StepId } from '@gridpilot/automation/domain/value-objects/StepId';
|
||||
import type {
|
||||
AutomationResult,
|
||||
ClickResult,
|
||||
FormFillResult,
|
||||
} from '../../../../application/ports/AutomationResults';
|
||||
import type { IAuthenticationService } from '../../../../application/ports/IAuthenticationService';
|
||||
import type { ILogger } from '../../../../application/ports/ILogger';
|
||||
import { CheckoutPrice } from '@gridpilot/automation/domain/value-objects/CheckoutPrice';
|
||||
import { CheckoutState } from '@gridpilot/automation/domain/value-objects/CheckoutState';
|
||||
import { CheckoutConfirmation } from '@gridpilot/automation/domain/value-objects/CheckoutConfirmation';
|
||||
import { StepId } from '../../../../domain/value-objects/StepId';
|
||||
import type { AutomationResultDTO } from '../../../../application/dto/AutomationResultDTO';
|
||||
import type { ClickResultDTO } from '../../../../application/dto/ClickResultDTO';
|
||||
import type { FormFillResultDTO } from '../../../../application/dto/FormFillResultDTO';
|
||||
import type { AuthenticationServicePort } from '../../../../application/ports/AuthenticationServicePort';
|
||||
import type { LoggerPort } from '../../../../application/ports/LoggerPort';
|
||||
import { CheckoutPrice } from '../../../../domain/value-objects/CheckoutPrice';
|
||||
import { CheckoutState } from '../../../../domain/value-objects/CheckoutState';
|
||||
import { CheckoutConfirmation } from '../../../../domain/value-objects/CheckoutConfirmation';
|
||||
import type { PlaywrightConfig } from './PlaywrightAutomationAdapter';
|
||||
import { PlaywrightBrowserSession } from './PlaywrightBrowserSession';
|
||||
import { IRacingDomNavigator } from '../dom/IRacingDomNavigator';
|
||||
@@ -19,16 +17,16 @@ import { getFixtureForStep } from '../engine/FixtureServer';
|
||||
import type {
|
||||
PageStateValidation,
|
||||
PageStateValidationResult,
|
||||
} from '@gridpilot/automation/domain/services/PageStateValidator';
|
||||
import type { Result } from '../../../../shared/result/Result';
|
||||
} from '../../../../domain/services/PageStateValidator';
|
||||
import type { Result } from '../../../../../shared/result/Result';
|
||||
|
||||
interface WizardStepOrchestratorDeps {
|
||||
config: Required<PlaywrightConfig>;
|
||||
browserSession: PlaywrightBrowserSession;
|
||||
navigator: IRacingDomNavigator;
|
||||
interactor: IRacingDomInteractor;
|
||||
authService: IAuthenticationService;
|
||||
logger?: ILogger;
|
||||
authService: AuthenticationServicePort;
|
||||
logger?: LoggerPort;
|
||||
totalSteps: number;
|
||||
getCheckoutConfirmationCallback: () =>
|
||||
| ((
|
||||
@@ -56,7 +54,7 @@ interface WizardStepOrchestratorDeps {
|
||||
dismissDatetimePickers(): Promise<void>;
|
||||
};
|
||||
helpers: {
|
||||
handleLogin(): Promise<AutomationResult>;
|
||||
handleLogin(): Promise<AutomationResultDTO>;
|
||||
validatePageState(
|
||||
validation: PageStateValidation,
|
||||
): Promise<Result<PageStateValidationResult, Error>>;
|
||||
@@ -69,8 +67,8 @@ export class WizardStepOrchestrator {
|
||||
private readonly browserSession: PlaywrightBrowserSession;
|
||||
private readonly navigator: IRacingDomNavigator;
|
||||
private readonly interactor: IRacingDomInteractor;
|
||||
private readonly authService: IAuthenticationService;
|
||||
private readonly logger?: ILogger;
|
||||
private readonly authService: AuthenticationServicePort;
|
||||
private readonly logger?: LoggerPort;
|
||||
private readonly totalSteps: number;
|
||||
private readonly getCheckoutConfirmationCallbackInternal: WizardStepOrchestratorDeps['getCheckoutConfirmationCallback'];
|
||||
private readonly overlay: WizardStepOrchestratorDeps['overlay'];
|
||||
@@ -139,7 +137,7 @@ export class WizardStepOrchestrator {
|
||||
await this.guards.dismissModals();
|
||||
}
|
||||
|
||||
private async handleLogin(): Promise<AutomationResult> {
|
||||
private async handleLogin(): Promise<AutomationResultDTO> {
|
||||
return this.helpers.handleLogin();
|
||||
}
|
||||
|
||||
@@ -147,14 +145,14 @@ export class WizardStepOrchestrator {
|
||||
await this.navigator.waitForStep(stepNumber);
|
||||
}
|
||||
|
||||
private async clickAction(action: string): Promise<ClickResult> {
|
||||
private async clickAction(action: string): Promise<ClickResultDTO> {
|
||||
return this.interactor.clickAction(action);
|
||||
}
|
||||
|
||||
private async fillFieldWithFallback(
|
||||
fieldName: string,
|
||||
value: string,
|
||||
): Promise<FormFillResult> {
|
||||
): Promise<FormFillResultDTO> {
|
||||
return this.interactor.fillFieldWithFallback(fieldName, value);
|
||||
}
|
||||
|
||||
@@ -200,7 +198,7 @@ export class WizardStepOrchestrator {
|
||||
private async fillField(
|
||||
fieldName: string,
|
||||
value: string,
|
||||
): Promise<FormFillResult> {
|
||||
): Promise<FormFillResultDTO> {
|
||||
return this.interactor.fillField(fieldName, value);
|
||||
}
|
||||
|
||||
@@ -266,7 +264,7 @@ export class WizardStepOrchestrator {
|
||||
async executeStep(
|
||||
stepId: StepId,
|
||||
config: Record<string, unknown>,
|
||||
): Promise<AutomationResult> {
|
||||
): Promise<AutomationResultDTO> {
|
||||
if (!this.page) {
|
||||
return { success: false, error: 'Browser not connected' };
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import type { Page } from 'playwright';
|
||||
import type { ILogger } from '../../../../application/ports/ILogger';
|
||||
import type {
|
||||
FormFillResult,
|
||||
ClickResult,
|
||||
ModalResult,
|
||||
} from '../../../../application/ports/AutomationResults';
|
||||
import { StepId } from '@gridpilot/automation/domain/value-objects/StepId';
|
||||
import type { LoggerPort } from '../../../../application/ports/LoggerPort';
|
||||
import type { FormFillResultDTO } from '../../../../application/dto/FormFillResultDTO';
|
||||
import type { ClickResultDTO } from '../../../../application/dto/ClickResultDTO';
|
||||
import type { ModalResultDTO } from '../../../../application/dto/ModalResultDTO';
|
||||
import { StepId } from '../../../../domain/value-objects/StepId';
|
||||
import type { PlaywrightConfig } from '../core/PlaywrightAutomationAdapter';
|
||||
import { PlaywrightBrowserSession } from '../core/PlaywrightBrowserSession';
|
||||
import { IRACING_SELECTORS, IRACING_TIMEOUTS } from './IRacingSelectors';
|
||||
@@ -17,7 +15,7 @@ export class IRacingDomInteractor {
|
||||
private readonly config: Required<PlaywrightConfig>,
|
||||
private readonly browserSession: PlaywrightBrowserSession,
|
||||
private readonly safeClickService: SafeClickService,
|
||||
private readonly logger?: ILogger,
|
||||
private readonly logger?: LoggerPort,
|
||||
) {}
|
||||
|
||||
private log(level: 'debug' | 'info' | 'warn' | 'error', message: string, context?: Record<string, unknown>): void {
|
||||
@@ -42,7 +40,7 @@ export class IRacingDomInteractor {
|
||||
|
||||
// ===== Public port-facing operations =====
|
||||
|
||||
async fillFormField(fieldName: string, value: string): Promise<FormFillResult> {
|
||||
async fillFormField(fieldName: string, value: string): Promise<FormFillResultDTO> {
|
||||
const page = this.browserSession.getPage();
|
||||
if (!page) {
|
||||
return { success: false, fieldName, valueSet: value, error: 'Browser not connected' };
|
||||
@@ -104,7 +102,7 @@ export class IRacingDomInteractor {
|
||||
}
|
||||
}
|
||||
|
||||
async clickElement(target: string): Promise<ClickResult> {
|
||||
async clickElement(target: string): Promise<ClickResultDTO> {
|
||||
const page = this.browserSession.getPage();
|
||||
if (!page) {
|
||||
return { success: false, target, error: 'Browser not connected' };
|
||||
@@ -124,7 +122,7 @@ export class IRacingDomInteractor {
|
||||
}
|
||||
}
|
||||
|
||||
async handleModal(stepId: StepId, action: string): Promise<ModalResult> {
|
||||
async handleModal(stepId: StepId, action: string): Promise<ModalResultDTO> {
|
||||
const page = this.browserSession.getPage();
|
||||
if (!page) {
|
||||
return { success: false, stepId: stepId.value, action, error: 'Browser not connected' };
|
||||
@@ -156,7 +154,7 @@ export class IRacingDomInteractor {
|
||||
|
||||
// ===== Public interaction helpers used by adapter steps =====
|
||||
|
||||
async fillField(fieldName: string, value: string): Promise<FormFillResult> {
|
||||
async fillField(fieldName: string, value: string): Promise<FormFillResultDTO> {
|
||||
const page = this.browserSession.getPage();
|
||||
if (!page) {
|
||||
return { success: false, fieldName, valueSet: value, error: 'Browser not connected' };
|
||||
@@ -208,7 +206,7 @@ export class IRacingDomInteractor {
|
||||
}
|
||||
}
|
||||
|
||||
async fillFieldWithFallback(fieldName: string, value: string): Promise<FormFillResult> {
|
||||
async fillFieldWithFallback(fieldName: string, value: string): Promise<FormFillResultDTO> {
|
||||
const page = this.browserSession.getPage();
|
||||
if (!page) {
|
||||
return { success: false, fieldName, valueSet: value, error: 'Browser not connected' };
|
||||
@@ -249,7 +247,7 @@ export class IRacingDomInteractor {
|
||||
}
|
||||
}
|
||||
|
||||
async clickAction(action: string): Promise<ClickResult> {
|
||||
async clickAction(action: string): Promise<ClickResultDTO> {
|
||||
const page = this.browserSession.getPage();
|
||||
if (!page) {
|
||||
return { success: false, target: action, error: 'Browser not connected' };
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { Page } from 'playwright';
|
||||
import type { ILogger } from '../../../../application/ports/ILogger';
|
||||
import type { NavigationResult, WaitResult } from '../../../../application/ports/AutomationResults';
|
||||
import type { LoggerPort } from '../../../../application/ports/LoggerPort';
|
||||
import type { NavigationResultDTO } from '../../../../application/dto/NavigationResultDTO';
|
||||
import type { WaitResultDTO } from '../../../../application/dto/WaitResultDTO';
|
||||
import type { PlaywrightConfig } from '../core/PlaywrightAutomationAdapter';
|
||||
import { PlaywrightBrowserSession } from '../core/PlaywrightBrowserSession';
|
||||
import { IRACING_SELECTORS, IRACING_TIMEOUTS, IRACING_URLS } from './IRacingSelectors';
|
||||
@@ -23,7 +24,7 @@ export class IRacingDomNavigator {
|
||||
constructor(
|
||||
private readonly config: Required<PlaywrightConfig>,
|
||||
private readonly browserSession: PlaywrightBrowserSession,
|
||||
private readonly logger?: ILogger,
|
||||
private readonly logger?: LoggerPort,
|
||||
private readonly onWizardDismissed?: () => Promise<void>,
|
||||
) {}
|
||||
|
||||
@@ -43,7 +44,7 @@ export class IRacingDomNavigator {
|
||||
return this.browserSession.getPage();
|
||||
}
|
||||
|
||||
async navigateToPage(url: string): Promise<NavigationResult> {
|
||||
async navigateToPage(url: string): Promise<NavigationResultDTO> {
|
||||
const page = this.getPage();
|
||||
if (!page) {
|
||||
return { success: false, url, loadTime: 0, error: 'Browser not connected' };
|
||||
@@ -78,7 +79,7 @@ export class IRacingDomNavigator {
|
||||
}
|
||||
}
|
||||
|
||||
async waitForElement(target: string, maxWaitMs?: number): Promise<WaitResult> {
|
||||
async waitForElement(target: string, maxWaitMs?: number): Promise<WaitResultDTO> {
|
||||
const page = this.getPage();
|
||||
if (!page) {
|
||||
return { success: false, target, waitedMs: 0, found: false, error: 'Browser not connected' };
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { Page } from 'playwright';
|
||||
import type { ILogger } from '../../../../application/ports/ILogger';
|
||||
import type { LoggerPort } from '@gridpilot/automation/application/ports/LoggerPort';
|
||||
import { IRACING_SELECTORS, BLOCKED_KEYWORDS } from './IRacingSelectors';
|
||||
import type { PlaywrightConfig } from '../core/PlaywrightAutomationAdapter';
|
||||
import { PlaywrightBrowserSession } from '../core/PlaywrightBrowserSession';
|
||||
@@ -8,7 +8,7 @@ export class SafeClickService {
|
||||
constructor(
|
||||
private readonly config: Required<PlaywrightConfig>,
|
||||
private readonly browserSession: PlaywrightBrowserSession,
|
||||
private readonly logger?: ILogger,
|
||||
private readonly logger?: LoggerPort,
|
||||
) {}
|
||||
|
||||
private log(level: 'debug' | 'info' | 'warn' | 'error', message: string, context?: Record<string, unknown>): void {
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import { IAutomationEngine, ValidationResult } from '../../../../application/ports/IAutomationEngine';
|
||||
import { HostedSessionConfig } from '@gridpilot/automation/domain/entities/HostedSessionConfig';
|
||||
import { StepId } from '@gridpilot/automation/domain/value-objects/StepId';
|
||||
import type { IBrowserAutomation } from '../../../../application/ports/IScreenAutomation';
|
||||
import { ISessionRepository } from '../../../../application/ports/ISessionRepository';
|
||||
import { StepTransitionValidator } from '@gridpilot/automation/domain/services/StepTransitionValidator';
|
||||
import type { AutomationEnginePort } from '../../../../application/ports/AutomationEnginePort';
|
||||
import { HostedSessionConfig } from '../../../../domain/entities/HostedSessionConfig';
|
||||
import { StepId } from '../../../../domain/value-objects/StepId';
|
||||
import type { IBrowserAutomation } from '../../../../application/ports/ScreenAutomationPort';
|
||||
import type { SessionRepositoryPort } from '../../../../application/ports/SessionRepositoryPort';
|
||||
import { StepTransitionValidator } from '../../../../domain/services/StepTransitionValidator';
|
||||
|
||||
type ValidationResult = {
|
||||
isValid: boolean;
|
||||
error?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Real Automation Engine Adapter.
|
||||
@@ -22,13 +27,13 @@ import { StepTransitionValidator } from '@gridpilot/automation/domain/services/S
|
||||
* browser automation when available. See docs/ARCHITECTURE.md
|
||||
* for the updated automation strategy.
|
||||
*/
|
||||
export class AutomationEngineAdapter implements IAutomationEngine {
|
||||
export class AutomationEngineAdapter implements AutomationEnginePort {
|
||||
private isRunning = false;
|
||||
private automationPromise: Promise<void> | null = null;
|
||||
|
||||
constructor(
|
||||
private readonly browserAutomation: IBrowserAutomation,
|
||||
private readonly sessionRepository: ISessionRepository
|
||||
private readonly sessionRepository: SessionRepositoryPort
|
||||
) {}
|
||||
|
||||
async validateConfiguration(config: HostedSessionConfig): Promise<ValidationResult> {
|
||||
|
||||
@@ -1,17 +1,22 @@
|
||||
import { IAutomationEngine, ValidationResult } from '../../../../application/ports/IAutomationEngine';
|
||||
import { HostedSessionConfig } from '@gridpilot/automation/domain/entities/HostedSessionConfig';
|
||||
import { StepId } from '@gridpilot/automation/domain/value-objects/StepId';
|
||||
import type { IBrowserAutomation } from '../../../../application/ports/IScreenAutomation';
|
||||
import { ISessionRepository } from '../../../../application/ports/ISessionRepository';
|
||||
import { StepTransitionValidator } from '@gridpilot/automation/domain/services/StepTransitionValidator';
|
||||
import type { AutomationEnginePort } from '../../../../application/ports/AutomationEnginePort';
|
||||
import { HostedSessionConfig } from '../../../../domain/entities/HostedSessionConfig';
|
||||
import { StepId } from '../../../../domain/value-objects/StepId';
|
||||
import type { IBrowserAutomation } from '../../../../application/ports/ScreenAutomationPort';
|
||||
import type { SessionRepositoryPort } from '../../../../application/ports/SessionRepositoryPort';
|
||||
import { StepTransitionValidator } from '../../../../domain/services/StepTransitionValidator';
|
||||
|
||||
export class MockAutomationEngineAdapter implements IAutomationEngine {
|
||||
type ValidationResult = {
|
||||
isValid: boolean;
|
||||
error?: string;
|
||||
};
|
||||
|
||||
export class MockAutomationEngineAdapter implements AutomationEnginePort {
|
||||
private isRunning = false;
|
||||
private automationPromise: Promise<void> | null = null;
|
||||
|
||||
constructor(
|
||||
private readonly browserAutomation: IBrowserAutomation,
|
||||
private readonly sessionRepository: ISessionRepository
|
||||
private readonly sessionRepository: SessionRepositoryPort
|
||||
) {}
|
||||
|
||||
async validateConfiguration(config: HostedSessionConfig): Promise<ValidationResult> {
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { StepId } from '@gridpilot/automation/domain/value-objects/StepId';
|
||||
import type { IBrowserAutomation } from '../../../../application/ports/IScreenAutomation';
|
||||
import {
|
||||
NavigationResult,
|
||||
FormFillResult,
|
||||
ClickResult,
|
||||
WaitResult,
|
||||
ModalResult,
|
||||
AutomationResult,
|
||||
} from '../../../../application/ports/AutomationResults';
|
||||
import { StepId } from '../../../../domain/value-objects/StepId';
|
||||
import type { IBrowserAutomation } from '../../../../application/ports/ScreenAutomationPort';
|
||||
import type { NavigationResultDTO } from '../../../../application/dto/NavigationResultDTO';
|
||||
import type { FormFillResultDTO } from '../../../../application/dto/FormFillResultDTO';
|
||||
import type { ClickResultDTO } from '../../../../application/dto/ClickResultDTO';
|
||||
import type { WaitResultDTO } from '../../../../application/dto/WaitResultDTO';
|
||||
import type { ModalResultDTO } from '../../../../application/dto/ModalResultDTO';
|
||||
import type { AutomationResultDTO } from '../../../../application/dto/AutomationResultDTO';
|
||||
|
||||
interface MockConfig {
|
||||
simulateFailures?: boolean;
|
||||
@@ -37,7 +35,7 @@ export class MockBrowserAutomationAdapter implements IBrowserAutomation {
|
||||
};
|
||||
}
|
||||
|
||||
async connect(): Promise<AutomationResult> {
|
||||
async connect(): Promise<AutomationResultDTO> {
|
||||
this.connected = true;
|
||||
return { success: true };
|
||||
}
|
||||
@@ -50,7 +48,7 @@ export class MockBrowserAutomationAdapter implements IBrowserAutomation {
|
||||
return this.connected;
|
||||
}
|
||||
|
||||
async navigateToPage(url: string): Promise<NavigationResult> {
|
||||
async navigateToPage(url: string): Promise<NavigationResultDTO> {
|
||||
const delay = this.randomDelay(200, 800);
|
||||
await this.sleep(delay);
|
||||
return {
|
||||
@@ -60,7 +58,7 @@ export class MockBrowserAutomationAdapter implements IBrowserAutomation {
|
||||
};
|
||||
}
|
||||
|
||||
async fillFormField(fieldName: string, value: string): Promise<FormFillResult> {
|
||||
async fillFormField(fieldName: string, value: string): Promise<FormFillResultDTO> {
|
||||
const delay = this.randomDelay(100, 500);
|
||||
await this.sleep(delay);
|
||||
return {
|
||||
@@ -70,7 +68,7 @@ export class MockBrowserAutomationAdapter implements IBrowserAutomation {
|
||||
};
|
||||
}
|
||||
|
||||
async clickElement(selector: string): Promise<ClickResult> {
|
||||
async clickElement(selector: string): Promise<ClickResultDTO> {
|
||||
const delay = this.randomDelay(50, 300);
|
||||
await this.sleep(delay);
|
||||
return {
|
||||
@@ -79,7 +77,7 @@ export class MockBrowserAutomationAdapter implements IBrowserAutomation {
|
||||
};
|
||||
}
|
||||
|
||||
async waitForElement(selector: string, maxWaitMs: number = 5000): Promise<WaitResult> {
|
||||
async waitForElement(selector: string, maxWaitMs: number = 5000): Promise<WaitResultDTO> {
|
||||
const delay = this.randomDelay(100, 1000);
|
||||
|
||||
await this.sleep(delay);
|
||||
@@ -92,7 +90,7 @@ export class MockBrowserAutomationAdapter implements IBrowserAutomation {
|
||||
};
|
||||
}
|
||||
|
||||
async handleModal(stepId: StepId, action: string): Promise<ModalResult> {
|
||||
async handleModal(stepId: StepId, action: string): Promise<ModalResultDTO> {
|
||||
if (!stepId.isModalStep()) {
|
||||
throw new Error(`Step ${stepId.value} is not a modal step`);
|
||||
}
|
||||
@@ -106,7 +104,7 @@ export class MockBrowserAutomationAdapter implements IBrowserAutomation {
|
||||
};
|
||||
}
|
||||
|
||||
async executeStep(stepId: StepId, config: Record<string, unknown>): Promise<AutomationResult> {
|
||||
async executeStep(stepId: StepId, config: Record<string, unknown>): Promise<AutomationResultDTO> {
|
||||
if (this.shouldSimulateFailure()) {
|
||||
throw new Error(`Simulated failure at step ${stepId.value}`);
|
||||
}
|
||||
|
||||
@@ -5,11 +5,12 @@
|
||||
|
||||
import type { BrowserWindow } from 'electron';
|
||||
import { ipcMain } from 'electron';
|
||||
import { Result } from '../../../shared/result/Result';
|
||||
import type { ICheckoutConfirmationPort, CheckoutConfirmationRequest } from '../../../application/ports/ICheckoutConfirmationPort';
|
||||
import { CheckoutConfirmation } from '@gridpilot/automation/domain/value-objects/CheckoutConfirmation';
|
||||
import { Result } from '../../../../shared/result/Result';
|
||||
import type { CheckoutConfirmationPort } from '../../../application/ports/CheckoutConfirmationPort';
|
||||
import type { CheckoutConfirmationRequestDTO } from '../../../application/dto/CheckoutConfirmationRequestDTO';
|
||||
import { CheckoutConfirmation } from '../../../domain/value-objects/CheckoutConfirmation';
|
||||
|
||||
export class ElectronCheckoutConfirmationAdapter implements ICheckoutConfirmationPort {
|
||||
export class ElectronCheckoutConfirmationAdapter implements CheckoutConfirmationPort {
|
||||
private mainWindow: BrowserWindow;
|
||||
private pendingConfirmation: {
|
||||
resolve: (confirmation: CheckoutConfirmation) => void;
|
||||
@@ -40,7 +41,7 @@ export class ElectronCheckoutConfirmationAdapter implements ICheckoutConfirmatio
|
||||
}
|
||||
|
||||
async requestCheckoutConfirmation(
|
||||
request: CheckoutConfirmationRequest
|
||||
request: CheckoutConfirmationRequestDTO
|
||||
): Promise<Result<CheckoutConfirmation>> {
|
||||
try {
|
||||
// Only allow one pending confirmation at a time
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { ILogger, LogContext } from '../../../application/ports/ILogger';
|
||||
import type { LoggerPort } from '../../../application/ports/LoggerPort';
|
||||
import type { LogContext } from '../../../application/ports/LoggerContext';
|
||||
|
||||
export class NoOpLogAdapter implements ILogger {
|
||||
export class NoOpLogAdapter implements LoggerPort {
|
||||
debug(_message: string, _context?: LogContext): void {}
|
||||
|
||||
info(_message: string, _context?: LogContext): void {}
|
||||
@@ -11,7 +12,7 @@ export class NoOpLogAdapter implements ILogger {
|
||||
|
||||
fatal(_message: string, _error?: Error, _context?: LogContext): void {}
|
||||
|
||||
child(_context: LogContext): ILogger {
|
||||
child(_context: LogContext): LoggerPort {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import type { ILogger, LogContext, LogLevel } from '../../../application/ports/ILogger';
|
||||
import type { LoggerPort } from '@gridpilot/automation/application/ports/LoggerPort';
|
||||
import type { LogContext } from '@gridpilot/automation/application/ports/LoggerContext';
|
||||
import type { LogLevel } from '@gridpilot/automation/application/ports/LoggerLogLevel';
|
||||
import { loadLoggingConfig, type LoggingEnvironmentConfig } from '../../config/LoggingConfig';
|
||||
|
||||
const LOG_LEVEL_PRIORITY: Record<LogLevel, number> = {
|
||||
@@ -18,7 +20,7 @@ const LOG_LEVEL_PRIORITY: Record<LogLevel, number> = {
|
||||
*
|
||||
* This provides structured JSON logging to stdout with the same interface.
|
||||
*/
|
||||
export class PinoLogAdapter implements ILogger {
|
||||
export class PinoLogAdapter implements LoggerPort {
|
||||
private readonly config: LoggingEnvironmentConfig;
|
||||
private readonly baseContext: LogContext;
|
||||
private readonly levelPriority: number;
|
||||
@@ -106,7 +108,7 @@ export class PinoLogAdapter implements ILogger {
|
||||
this.log('fatal', message, context, error);
|
||||
}
|
||||
|
||||
child(context: LogContext): ILogger {
|
||||
child(context: LogContext): LoggerPort {
|
||||
return new PinoLogAdapter(this.config, { ...this.baseContext, ...context });
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { LogLevel } from '../../application/ports/ILogger';
|
||||
import type { LogLevel } from '@gridpilot/automation/application/ports/LoggerLogLevel';
|
||||
|
||||
export type LogEnvironment = 'development' | 'production' | 'test';
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { AutomationSession } from '@gridpilot/automation/domain/entities/AutomationSession';
|
||||
import { SessionStateValue } from '@gridpilot/automation/domain/value-objects/SessionState';
|
||||
import { ISessionRepository } from '../../application/ports/ISessionRepository';
|
||||
import { AutomationSession } from '../../domain/entities/AutomationSession';
|
||||
import { SessionStateValue } from '../../domain/value-objects/SessionState';
|
||||
import type { SessionRepositoryPort } from '../../application/ports/SessionRepositoryPort';
|
||||
|
||||
export class InMemorySessionRepository implements ISessionRepository {
|
||||
export class InMemorySessionRepository implements SessionRepositoryPort {
|
||||
private sessions: Map<string, AutomationSession> = new Map();
|
||||
|
||||
async save(session: AutomationSession): Promise<void> {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": ".",
|
||||
"rootDir": "..",
|
||||
"outDir": "dist",
|
||||
"declaration": true,
|
||||
"declarationMap": false
|
||||
|
||||
Reference in New Issue
Block a user