This commit is contained in:
2025-12-16 11:09:13 +01:00
parent 8ed6ba1fd1
commit ce82b7822b
64 changed files with 521 additions and 328 deletions

View File

@@ -9,6 +9,9 @@
"ecmaVersion": 2022 "ecmaVersion": 2022
}, },
"settings": { "settings": {
"import/resolver": {
"typescript": {}
},
"boundaries/elements": [ "boundaries/elements": [
{ {
"type": "website", "type": "website",
@@ -20,11 +23,11 @@
}, },
{ {
"type": "adapters", "type": "adapters",
"pattern": "adapters/**/*" "pattern": ["adapters/**/*", "@adapters/**/*"]
}, },
{ {
"type": "core", "type": "core",
"pattern": "core/**/*" "pattern": ["core/**/*", "@core/**/*"]
} }
] ]
}, },

View File

@@ -1,136 +1,97 @@
# 🧭 Orchestrator # 🧭 Orchestrator
## Purpose ## Purpose
Interpret the users intent, collect all required context, Interpret the users intent, gather context, maintain the TODO list,
decide **what must be done**, and delegate **clearly scoped tasks** to the correct expert. and delegate work in the correct order.
The Orchestrator does NOT: The Orchestrator coordinates.
- perform expert work It does not execute.
- analyze architecture
- design solutions
- implement logic
- define expert output formats
--- ---
## User Supremacy ## User Supremacy
- The user is the absolute highest authority. - The user is the highest authority.
- Any user instruction overrides all rules and processes. - Any new user instruction immediately interrupts all ongoing work.
- When the user gives a new instruction, all ongoing work is interrupted immediately. - No reinterpretation, no negotiation.
- No reinterpretation, no negotiation, no resistance.
--- ---
## Context Responsibility (Critical) ## TODO List Is the Source of Truth (Critical)
The Orchestrator is the **only role allowed to gather or interpret context**. The TODO list represents **all remaining work**.
The Orchestrator MUST: Rules:
- identify all relevant files - Only the Orchestrator owns the TODO list.
- identify which parts are already done - Experts never modify TODOs directly.
- identify what is still missing - The Orchestrator must keep the TODO list accurate at all times.
- extract only relevant information
- pass **complete, explicit context** to experts
Experts MUST NOT:
- scan the repository
- infer missing information
- rediscover context
If an expert requests missing context, the Orchestrator must provide it immediately.
--- ---
## Domain Routing (Mandatory) ## Handling Expert Results (Mandatory)
Before delegating any task, the Orchestrator MUST decide **exactly one domain**: When an expert returns a result, the Orchestrator MUST do the following **in order**:
- Frontend 1. **Read “What is still open”**
OR 2. If it is:
- Backend (Coder) - “Nothing” → proceed
- a list of items → STOP and update the TODO list
3. Convert each open item into a TODO entry
4. Remove completed TODOs
5. Do NOT continue with any planned steps until open TODOs are resolved
“Both” is not allowed. The Orchestrator MUST NOT:
- ignore open items
If a user instruction touches frontend and backend: - assume they are handled later
- split into separate tasks - continue a multi-step plan automatically
- delegate each task independently - delegate the next planned step while TODOs exist
- never mix domains in a single task
--- ---
## Information Gathering Order ## Progress Rule (Hard Gate)
The Orchestrator MUST NOT rush to Architect or Coder. The Orchestrator may proceed to the next step ONLY when:
Before delegating, the Orchestrator MUST check: - the current TODO list is empty
OR
- the user explicitly instructs to ignore open items
1. Is the user intent clear? No other condition allows forward progress.
2. Is all required information available?
3. Are assumptions being made?
4. Is this the correct next step?
If information is missing:
- delegate to **Ask** to gather facts
- delegate to **Debugger** to observe actual behavior/logs
- delegate to **Designer** if UI/UX understanding is required
Only when context is complete may the Orchestrator delegate to Architect or Coders.
--- ---
## Task Grouping ## Delegation Rule
The Orchestrator MUST: When delegating:
- bundle work that belongs to the same goal and same domain - delegate ONLY the next TODO
- split work that does not belong together - include full context
- avoid micro-tasks - scope to a single purpose
- avoid over-scoped tasks - assign to exactly one expert
Each delegated task must be: Never delegate multiple TODOs at once unless they are explicitly bundled.
- single-purpose
- fully scoped
- executable without guessing
--- ---
## TODO List (Required) ## Planning Discipline
When the user gives a task, the Orchestrator MUST: The Orchestrator must NOT treat a plan as a script.
1. Create a TODO list containing **only outstanding work**. Plans are:
2. Exclude anything already completed. - intentions
3. Update the TODO list after every expert result. - not guarantees
4. Remove completed items immediately. - always subordinate to actual execution results
5. Never invent TODOs.
The TODO list is the **single source of truth** for remaining work. Reality (expert output) always overrides plan order.
---
## Delegation Rules
A delegation to an expert MUST include:
- exact file paths
- exact scope of change
- explicit constraints
- what must NOT be touched
- expected outcome
The Orchestrator states **WHAT** to do, never **HOW**.
--- ---
## Forbidden ## Forbidden
The Orchestrator MUST NOT: The Orchestrator MUST NOT:
- perform expert analysis - continue a plan when TODOs remain
- solve problems itself - treat “still open” as informational only
- explain architecture or design - assume the expert will handle remaining work implicitly
- define deliverables for experts - batch unresolved items
- define expert completion formats - skip TODO reconciliation
- rush to execution - push work forward “for momentum”
- delegate with incomplete context
- merge frontend and backend work
- generate long explanations
- override user intent
--- ---
## Completion ## Completion
A step is complete when: A workflow step is complete ONLY when:
- the expert finishes the delegated task - the expert reports “What is still open: Nothing”
- the TODO list reflects only remaining work - the TODO list is empty
- the Orchestrator either delegates the next task or waits for user input - or the user explicitly overrides and says to proceed anyway

View File

@@ -1,7 +1,7 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from '@nestjs/typeorm';
import { AnalyticsSnapshotOrmEntity } from '../../../../../adapters/persistence/typeorm/analytics/AnalyticsSnapshotOrmEntity'; import { AnalyticsSnapshotOrmEntity } from '../../../../..//persistence/typeorm/analytics/AnalyticsSnapshotOrmEntity';
import { EngagementOrmEntity } from '../../../../../adapters/persistence/typeorm/analytics/EngagementOrmEntity'; import { EngagementOrmEntity } from '../../../../..//persistence/typeorm/analytics/EngagementOrmEntity';
@Module({ @Module({
imports: [ imports: [

View File

@@ -1,6 +1,6 @@
import { Global, Module } from '@nestjs/common'; import { Global, Module } from '@nestjs/common';
import { Logger } from '@gridpilot/shared/application/Logger'; import { Logger } from '@gridpilot/shared/application/Logger';
import { ConsoleLogger } from '@gridpilot/adapters/logging/ConsoleLogger'; import { ConsoleLogger } from '@gridpilot//logging/ConsoleLogger';
@Global() @Global()
@Module({ @Module({

View File

@@ -1,20 +1,26 @@
import { Provider } from '@nestjs/common'; import { Provider } from '@nestjs/common';
import { AnalyticsService } from './AnalyticsService'; import { AnalyticsService } from './AnalyticsService';
import { RecordPageViewUseCase } from './use-cases/RecordPageViewUseCase';
import { RecordEngagementUseCase } from './use-cases/RecordEngagementUseCase';
const Logger_TOKEN = 'Logger_TOKEN'; const Logger_TOKEN = 'Logger_TOKEN';
const IPAGE_VIEW_REPO_TOKEN = 'IPageViewRepository_TOKEN'; const IPAGE_VIEW_REPO_TOKEN = 'IPageViewRepository_TOKEN';
const IENGAGEMENT_REPO_TOKEN = 'IEngagementRepository_TOKEN'; const IENGAGEMENT_REPO_TOKEN = 'IEngagementRepository_TOKEN';
const RECORD_PAGE_VIEW_USE_CASE_TOKEN = 'RecordPageViewUseCase_TOKEN';
const RECORD_ENGAGEMENT_USE_CASE_TOKEN = 'RecordEngagementUseCase_TOKEN';
import { Logger } from '@gridpilot/shared/logging/Logger'; import { Logger } from '@gridpilot/shared/logging/Logger';
import { IPageViewRepository } from '@gridpilot/analytics/application/repositories/IPageViewRepository'; import { IPageViewRepository } from '@gridpilot/analytics/application/repositories/IPageViewRepository';
import { IEngagementRepository } from '@gridpilot/analytics/domain/repositories/IEngagementRepository'; import { IEngagementRepository } from '@gridpilot/analytics/domain/repositories/IEngagementRepository';
import { ConsoleLogger } from '../../../../adapters/logging/ConsoleLogger'; import { ConsoleLogger } from '../../../..//logging/ConsoleLogger';
import { InMemoryPageViewRepository } from '../../../../adapters/analytics/persistence/inmemory/InMemoryPageViewRepository'; import { InMemoryPageViewRepository } from '../../../..//analytics/persistence/inmemory/InMemoryPageViewRepository';
import { InMemoryEngagementRepository } from '../../../../adapters/analytics/persistence/inmemory/InMemoryEngagementRepository'; import { InMemoryEngagementRepository } from '../../../..//analytics/persistence/inmemory/InMemoryEngagementRepository';
export const AnalyticsProviders: Provider[] = [ export const AnalyticsProviders: Provider[] = [
AnalyticsService, AnalyticsService,
RecordPageViewUseCase,
RecordEngagementUseCase,
{ {
provide: Logger_TOKEN, provide: Logger_TOKEN,
useClass: ConsoleLogger, useClass: ConsoleLogger,
@@ -27,4 +33,12 @@ export const AnalyticsProviders: Provider[] = [
provide: IENGAGEMENT_REPO_TOKEN, provide: IENGAGEMENT_REPO_TOKEN,
useClass: InMemoryEngagementRepository, useClass: InMemoryEngagementRepository,
}, },
{
provide: RECORD_PAGE_VIEW_USE_CASE_TOKEN,
useClass: RecordPageViewUseCase,
},
{
provide: RECORD_ENGAGEMENT_USE_CASE_TOKEN,
useClass: RecordEngagementUseCase,
},
]; ];

View File

@@ -1,83 +1,26 @@
import { Injectable, Inject } from '@nestjs/common'; import { Injectable, Inject } from '@nestjs/common';
import { RecordEngagementInput, RecordEngagementOutput, RecordPageViewInput, RecordPageViewOutput } from './dto/AnalyticsDto'; import { RecordEngagementInput, RecordEngagementOutput, RecordPageViewInput, RecordPageViewOutput } from './dto/AnalyticsDto';
import { IPageViewRepository } from '@gridpilot/analytics/application/repositories/IPageViewRepository';
import { IEngagementRepository } from '@gridpilot/analytics/domain/repositories/IEngagementRepository';
import { Logger } from '@gridpilot/shared/logging/Logger'; import { Logger } from '@gridpilot/shared/logging/Logger';
import { PageView } from '@gridpilot/analytics/domain/entities/PageView'; import { RecordPageViewUseCase } from './use-cases/RecordPageViewUseCase';
import { EngagementEvent } from '@gridpilot/analytics/domain/entities/EngagementEvent'; import { RecordEngagementUseCase } from './use-cases/RecordEngagementUseCase';
const Logger_TOKEN = 'Logger_TOKEN'; const Logger_TOKEN = 'Logger_TOKEN';
const IPAGE_VIEW_REPO_TOKEN = 'IPageViewRepository_TOKEN'; const RECORD_PAGE_VIEW_USE_CASE_TOKEN = 'RecordPageViewUseCase_TOKEN';
const IENGAGEMENT_REPO_TOKEN = 'IEngagementRepository_TOKEN'; const RECORD_ENGAGEMENT_USE_CASE_TOKEN = 'RecordEngagementUseCase_TOKEN';
@Injectable() @Injectable()
export class AnalyticsService { export class AnalyticsService {
constructor( constructor(
@Inject(IPAGE_VIEW_REPO_TOKEN) private readonly pageViewRepository: IPageViewRepository, @Inject(RECORD_PAGE_VIEW_USE_CASE_TOKEN) private readonly recordPageViewUseCase: RecordPageViewUseCase,
@Inject(IENGAGEMENT_REPO_TOKEN) private readonly engagementRepository: IEngagementRepository, @Inject(RECORD_ENGAGEMENT_USE_CASE_TOKEN) private readonly recordEngagementUseCase: RecordEngagementUseCase,
@Inject(Logger_TOKEN) private readonly logger: Logger, @Inject(Logger_TOKEN) private readonly logger: Logger,
) {} ) {}
async recordPageView(input: RecordPageViewInput): Promise<RecordPageViewOutput> { async recordPageView(input: RecordPageViewInput): Promise<RecordPageViewOutput> {
this.logger.debug('Executing RecordPageViewUseCase', { input }); return await this.recordPageViewUseCase.execute(input);
try {
const pageViewId = `pv-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
const baseProps: Omit<Parameters<typeof PageView.create>[0], 'timestamp'> = {
id: pageViewId,
entityType: input.entityType as any, // Cast to any to bypass strict type checking, will resolve with proper domain layer alignment
entityId: input.entityId,
visitorType: input.visitorType as any, // Cast to any to bypass strict type checking, will resolve with proper domain layer alignment
sessionId: input.sessionId,
};
const pageView = PageView.create({
...baseProps,
...(input.visitorId !== undefined ? { visitorId: input.visitorId } : {}),
...(input.referrer !== undefined ? { referrer: input.referrer } : {}),
...(input.userAgent !== undefined ? { userAgent: input.userAgent } : {}),
...(input.country !== undefined ? { country: input.country } : {}),
});
await this.pageViewRepository.save(pageView);
this.logger.info('Page view recorded successfully', { pageViewId, input });
return { pageViewId };
} catch (error) {
this.logger.error('Error recording page view', error, { input });
throw error;
}
} }
async recordEngagement(input: RecordEngagementInput): Promise<RecordEngagementOutput> { async recordEngagement(input: RecordEngagementInput): Promise<RecordEngagementOutput> {
this.logger.debug('Executing RecordEngagementUseCase', { input }); return await this.recordEngagementUseCase.execute(input);
try {
const eventId = `eng-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
const baseProps: Omit<Parameters<typeof EngagementEvent.create>[0], 'timestamp'> = {
id: eventId,
action: input.action as any, // Cast to any to bypass strict type checking, will resolve with proper domain layer alignment
entityType: input.entityType as any, // Cast to any to bypass strict type checking, will resolve with proper domain layer alignment
entityId: input.entityId,
actorType: input.actorType,
sessionId: input.sessionId,
};
const event = EngagementEvent.create({
...baseProps,
...(input.actorId !== undefined ? { actorId: input.actorId } : {}),
...(input.metadata !== undefined ? { metadata: input.metadata } : {}),
});
await this.engagementRepository.save(event);
this.logger.info('Engagement recorded successfully', { eventId, input });
return {
eventId,
engagementWeight: event.getEngagementWeight(),
};
} catch (error) {
this.logger.error('Error recording engagement', error, { input });
throw error;
}
} }
} }

View File

@@ -0,0 +1,88 @@
import { Test, TestingModule } from '@nestjs/testing';
import { RecordEngagementUseCase } from './RecordEngagementUseCase';
import { IEngagementRepository } from '@gridpilot/analytics/domain/repositories/IEngagementRepository';
import { Logger } from '@gridpilot/shared/logging/Logger';
describe('RecordEngagementUseCase', () => {
let useCase: RecordEngagementUseCase;
let engagementRepository: jest.Mocked<IEngagementRepository>;
let logger: jest.Mocked<Logger>;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
RecordEngagementUseCase,
{
provide: 'IEngagementRepository_TOKEN',
useValue: {
save: jest.fn(),
},
},
{
provide: 'Logger_TOKEN',
useValue: {
debug: jest.fn(),
info: jest.fn(),
error: jest.fn(),
},
},
],
}).compile();
useCase = module.get<RecordEngagementUseCase>(RecordEngagementUseCase);
engagementRepository = module.get('IEngagementRepository_TOKEN');
logger = module.get('Logger_TOKEN');
});
describe('execute', () => {
it('should save the engagement event and return the eventId and engagementWeight', async () => {
const input = {
action: 'like' as any,
entityType: 'race' as any,
entityId: 'race-123',
actorType: 'driver',
sessionId: 'session-456',
actorId: 'actor-789',
metadata: { some: 'data' },
};
const mockEvent = {
getEngagementWeight: jest.fn().mockReturnValue(10),
};
// Mock the create function to return the mock event
const originalCreate = require('@gridpilot/analytics/domain/entities/EngagementEvent').EngagementEvent.create;
require('@gridpilot/analytics/domain/entities/EngagementEvent').EngagementEvent.create = jest.fn().mockReturnValue(mockEvent);
engagementRepository.save.mockResolvedValue(undefined);
const result = await useCase.execute(input);
expect(logger.debug).toHaveBeenCalledWith('Executing RecordEngagementUseCase', { input });
expect(engagementRepository.save).toHaveBeenCalledWith(mockEvent);
expect(logger.info).toHaveBeenCalledWith('Engagement recorded successfully', expect.objectContaining({ eventId: expect.any(String), input }));
expect(result).toHaveProperty('eventId');
expect(result).toHaveProperty('engagementWeight', 10);
expect(typeof result.eventId).toBe('string');
// Restore original
require('@gridpilot/analytics/domain/entities/EngagementEvent').EngagementEvent.create = originalCreate;
});
it('should handle errors and throw them', async () => {
const input = {
action: 'like' as any,
entityType: 'race' as any,
entityId: 'race-123',
actorType: 'driver',
sessionId: 'session-456',
};
const error = new Error('Save failed');
engagementRepository.save.mockRejectedValue(error);
await expect(useCase.execute(input)).rejects.toThrow('Save failed');
expect(logger.error).toHaveBeenCalledWith('Error recording engagement', error, { input });
});
});
});

View File

@@ -0,0 +1,49 @@
import { Injectable, Inject } from '@nestjs/common';
import { RecordEngagementInput, RecordEngagementOutput } from '../dto/AnalyticsDto';
import { IEngagementRepository } from '@gridpilot/analytics/domain/repositories/IEngagementRepository';
import { Logger } from '@gridpilot/shared/logging/Logger';
import { EngagementEvent } from '@gridpilot/analytics/domain/entities/EngagementEvent';
const Logger_TOKEN = 'Logger_TOKEN';
const IENGAGEMENT_REPO_TOKEN = 'IEngagementRepository_TOKEN';
@Injectable()
export class RecordEngagementUseCase {
constructor(
@Inject(IENGAGEMENT_REPO_TOKEN) private readonly engagementRepository: IEngagementRepository,
@Inject(Logger_TOKEN) private readonly logger: Logger,
) {}
async execute(input: RecordEngagementInput): Promise<RecordEngagementOutput> {
this.logger.debug('Executing RecordEngagementUseCase', { input });
try {
const eventId = `eng-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
const baseProps: Omit<Parameters<typeof EngagementEvent.create>[0], 'timestamp'> = {
id: eventId,
action: input.action as any, // Cast to any to bypass strict type checking, will resolve with proper domain layer alignment
entityType: input.entityType as any, // Cast to any to bypass strict type checking, will resolve with proper domain layer alignment
entityId: input.entityId,
actorType: input.actorType,
sessionId: input.sessionId,
};
const event = EngagementEvent.create({
...baseProps,
...(input.actorId !== undefined ? { actorId: input.actorId } : {}),
...(input.metadata !== undefined ? { metadata: input.metadata } : {}),
});
await this.engagementRepository.save(event);
this.logger.info('Engagement recorded successfully', { eventId, input });
return {
eventId,
engagementWeight: event.getEngagementWeight(),
};
} catch (error) {
this.logger.error('Error recording engagement', error, { input });
throw error;
}
}
}

View File

@@ -0,0 +1,76 @@
import { Test, TestingModule } from '@nestjs/testing';
import { RecordPageViewUseCase } from './RecordPageViewUseCase';
import { IPageViewRepository } from '@gridpilot/analytics/application/repositories/IPageViewRepository';
import { Logger } from '@gridpilot/shared/logging/Logger';
describe('RecordPageViewUseCase', () => {
let useCase: RecordPageViewUseCase;
let pageViewRepository: jest.Mocked<IPageViewRepository>;
let logger: jest.Mocked<Logger>;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
RecordPageViewUseCase,
{
provide: 'IPageViewRepository_TOKEN',
useValue: {
save: jest.fn(),
},
},
{
provide: 'Logger_TOKEN',
useValue: {
debug: jest.fn(),
info: jest.fn(),
error: jest.fn(),
},
},
],
}).compile();
useCase = module.get<RecordPageViewUseCase>(RecordPageViewUseCase);
pageViewRepository = module.get('IPageViewRepository_TOKEN');
logger = module.get('Logger_TOKEN');
});
describe('execute', () => {
it('should save the page view and return the pageViewId', async () => {
const input = {
entityType: 'race' as any,
entityId: 'race-123',
visitorType: 'anonymous' as any,
sessionId: 'session-456',
visitorId: 'visitor-789',
referrer: 'https://example.com',
userAgent: 'Mozilla/5.0',
country: 'US',
};
pageViewRepository.save.mockResolvedValue(undefined);
const result = await useCase.execute(input);
expect(logger.debug).toHaveBeenCalledWith('Executing RecordPageViewUseCase', { input });
expect(pageViewRepository.save).toHaveBeenCalledTimes(1);
expect(logger.info).toHaveBeenCalledWith('Page view recorded successfully', expect.objectContaining({ pageViewId: expect.any(String), input }));
expect(result).toHaveProperty('pageViewId');
expect(typeof result.pageViewId).toBe('string');
});
it('should handle errors and throw them', async () => {
const input = {
entityType: 'race' as any,
entityId: 'race-123',
visitorType: 'anonymous' as any,
sessionId: 'session-456',
};
const error = new Error('Save failed');
pageViewRepository.save.mockRejectedValue(error);
await expect(useCase.execute(input)).rejects.toThrow('Save failed');
expect(logger.error).toHaveBeenCalledWith('Error recording page view', error, { input });
});
});
});

View File

@@ -0,0 +1,46 @@
import { Injectable, Inject } from '@nestjs/common';
import { RecordPageViewInput, RecordPageViewOutput } from '../dto/AnalyticsDto';
import { IPageViewRepository } from '@gridpilot/analytics/application/repositories/IPageViewRepository';
import { Logger } from '@gridpilot/shared/logging/Logger';
import { PageView } from '@gridpilot/analytics/domain/entities/PageView';
const Logger_TOKEN = 'Logger_TOKEN';
const IPAGE_VIEW_REPO_TOKEN = 'IPageViewRepository_TOKEN';
@Injectable()
export class RecordPageViewUseCase {
constructor(
@Inject(IPAGE_VIEW_REPO_TOKEN) private readonly pageViewRepository: IPageViewRepository,
@Inject(Logger_TOKEN) private readonly logger: Logger,
) {}
async execute(input: RecordPageViewInput): Promise<RecordPageViewOutput> {
this.logger.debug('Executing RecordPageViewUseCase', { input });
try {
const pageViewId = `pv-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
const baseProps: Omit<Parameters<typeof PageView.create>[0], 'timestamp'> = {
id: pageViewId,
entityType: input.entityType as any, // Cast to any to bypass strict type checking, will resolve with proper domain layer alignment
entityId: input.entityId,
visitorType: input.visitorType as any, // Cast to any to bypass strict type checking, will resolve with proper domain layer alignment
sessionId: input.sessionId,
};
const pageView = PageView.create({
...baseProps,
...(input.visitorId !== undefined ? { visitorId: input.visitorId } : {}),
...(input.referrer !== undefined ? { referrer: input.referrer } : {}),
...(input.userAgent !== undefined ? { userAgent: input.userAgent } : {}),
...(input.country !== undefined ? { country: input.country } : {}),
});
await this.pageViewRepository.save(pageView);
this.logger.info('Page view recorded successfully', { pageViewId, input });
return { pageViewId };
} catch (error) {
this.logger.error('Error recording page view', error, { input });
throw error;
}
}
}

View File

@@ -7,12 +7,12 @@ import { IUserRepository, StoredUser } from '@gridpilot/core/identity/domain/rep
import { IPasswordHashingService } from '@gridpilot/core/identity/domain/services/PasswordHashingService'; import { IPasswordHashingService } from '@gridpilot/core/identity/domain/services/PasswordHashingService';
import { Logger } from '@gridpilot/core/shared/logging/Logger'; import { Logger } from '@gridpilot/core/shared/logging/Logger';
import { InMemoryAuthRepository } from '../../../adapters/identity/persistence/inmemory/InMemoryAuthRepository'; import { InMemoryAuthRepository } from '../../..//identity/persistence/inmemory/InMemoryAuthRepository';
import { InMemoryUserRepository } from '../../../adapters/identity/persistence/inmemory/InMemoryUserRepository'; import { InMemoryUserRepository } from '../../..//identity/persistence/inmemory/InMemoryUserRepository';
import { InMemoryPasswordHashingService } from '../../../adapters/identity/services/InMemoryPasswordHashingService'; import { InMemoryPasswordHashingService } from '../../..//identity/services/InMemoryPasswordHashingService';
import { ConsoleLogger } from '../../../adapters/logging/ConsoleLogger'; import { ConsoleLogger } from '../../..//logging/ConsoleLogger';
import { IdentitySessionPort } from '../../../../core/identity/application/ports/IdentitySessionPort'; // Path from apps/api/src/modules/auth import { IdentitySessionPort } from '../../../../core/identity/application/ports/IdentitySessionPort'; // Path from apps/api/src/modules/auth
import { CookieIdentitySessionAdapter } from '../../../adapters/identity/session/CookieIdentitySessionAdapter'; import { CookieIdentitySessionAdapter } from '../../..//identity/session/CookieIdentitySessionAdapter';
// Define the tokens for dependency injection // Define the tokens for dependency injection
export const AUTH_REPOSITORY_TOKEN = 'IAuthRepository'; export const AUTH_REPOSITORY_TOKEN = 'IAuthRepository';

View File

@@ -17,14 +17,14 @@ import { GetTotalDriversUseCase } from '../../../../core/racing/application/use-
import { CompleteDriverOnboardingUseCase } from '../../../../core/racing/application/use-cases/CompleteDriverOnboardingUseCase'; import { CompleteDriverOnboardingUseCase } from '../../../../core/racing/application/use-cases/CompleteDriverOnboardingUseCase';
// Import concrete in-memory implementations // Import concrete in-memory implementations
import { InMemoryDriverRepository } from '../../../adapters/racing/persistence/inmemory/InMemoryDriverRepository'; import { InMemoryDriverRepository } from '../../..//racing/persistence/inmemory/InMemoryDriverRepository';
import { InMemoryRankingService } from '../../../adapters/racing/services/InMemoryRankingService'; import { InMemoryRankingService } from '../../..//racing/services/InMemoryRankingService';
import { InMemoryDriverStatsService } from '../../../adapters/racing/services/InMemoryDriverStatsService'; import { InMemoryDriverStatsService } from '../../..//racing/services/InMemoryDriverStatsService';
import { InMemoryDriverRatingProvider } from '../../../adapters/racing/ports/InMemoryDriverRatingProvider'; import { InMemoryDriverRatingProvider } from '../../..//racing/ports/InMemoryDriverRatingProvider';
import { InMemoryImageServiceAdapter } from '../../../adapters/media/ports/InMemoryImageServiceAdapter'; import { InMemoryImageServiceAdapter } from '../../..//media/ports/InMemoryImageServiceAdapter';
import { InMemoryRaceRegistrationRepository } from '../../../adapters/racing/persistence/inmemory/InMemoryRaceRegistrationRepository'; import { InMemoryRaceRegistrationRepository } from '../../..//racing/persistence/inmemory/InMemoryRaceRegistrationRepository';
import { InMemoryNotificationPreferenceRepository } from '../../../adapters/notifications/persistence/inmemory/InMemoryNotificationPreferenceRepository'; import { InMemoryNotificationPreferenceRepository } from '../../..//notifications/persistence/inmemory/InMemoryNotificationPreferenceRepository';
import { ConsoleLogger } from '../../../adapters/logging/ConsoleLogger'; import { ConsoleLogger } from '../../..//logging/ConsoleLogger';
// Define injection tokens // Define injection tokens
export const DRIVER_REPOSITORY_TOKEN = 'IDriverRepository'; export const DRIVER_REPOSITORY_TOKEN = 'IDriverRepository';

View File

@@ -5,17 +5,17 @@ import { LeagueService } from './LeagueService';
import { Logger } from '@gridpilot/shared/application/Logger'; import { Logger } from '@gridpilot/shared/application/Logger';
// Import concrete in-memory implementations // Import concrete in-memory implementations
import { InMemoryLeagueRepository } from 'adapters/racing/persistence/inmemory/InMemoryLeagueRepository'; import { InMemoryLeagueRepository } from '/racing/persistence/inmemory/InMemoryLeagueRepository';
import { InMemoryLeagueMembershipRepository } from 'adapters/racing/persistence/inmemory/InMemoryLeagueMembershipRepository'; import { InMemoryLeagueMembershipRepository } from '/racing/persistence/inmemory/InMemoryLeagueMembershipRepository';
import { InMemoryLeagueStandingsRepository } from 'adapters/racing/persistence/inmemory/InMemoryLeagueStandingsRepository'; import { InMemoryLeagueStandingsRepository } from '/racing/persistence/inmemory/InMemoryLeagueStandingsRepository';
import { InMemorySeasonRepository } from 'adapters/racing/persistence/inmemory/InMemorySeasonRepository'; import { InMemorySeasonRepository } from '/racing/persistence/inmemory/InMemorySeasonRepository';
import { InMemoryLeagueScoringConfigRepository } from 'adapters/racing/persistence/inmemory/InMemoryLeagueScoringConfigRepository'; import { InMemoryLeagueScoringConfigRepository } from '/racing/persistence/inmemory/InMemoryLeagueScoringConfigRepository';
import { InMemoryGameRepository } from 'adapters/racing/persistence/inmemory/InMemoryGameRepository'; import { InMemoryGameRepository } from '/racing/persistence/inmemory/InMemoryGameRepository';
import { InMemoryProtestRepository } from 'adapters/racing/persistence/inmemory/InMemoryProtestRepository'; import { InMemoryProtestRepository } from '/racing/persistence/inmemory/InMemoryProtestRepository';
import { InMemoryRaceRepository } from 'adapters/racing/persistence/inmemory/InMemoryRaceRepository'; import { InMemoryRaceRepository } from '/racing/persistence/inmemory/InMemoryRaceRepository';
import { InMemoryDriverRepository } from 'adapters/racing/persistence/inmemory/InMemoryDriverRepository'; import { InMemoryDriverRepository } from '/racing/persistence/inmemory/InMemoryDriverRepository';
import { InMemoryStandingRepository } from 'adapters/racing/persistence/inmemory/InMemoryStandingRepository'; import { InMemoryStandingRepository } from '/racing/persistence/inmemory/InMemoryStandingRepository';
import { ConsoleLogger } from 'adapters/logging/ConsoleLogger'; import { ConsoleLogger } from '/logging/ConsoleLogger';
// Import use cases // Import use cases
import { GetAllLeaguesWithCapacityUseCase } from '@gridpilot/racing/application/use-cases/GetAllLeaguesWithCapacityUseCase'; import { GetAllLeaguesWithCapacityUseCase } from '@gridpilot/racing/application/use-cases/GetAllLeaguesWithCapacityUseCase';

View File

@@ -23,11 +23,11 @@ import { GetWalletUseCase } from '@gridpilot/payments/application/use-cases/GetW
import { ProcessWalletTransactionUseCase } from '@gridpilot/payments/application/use-cases/ProcessWalletTransactionUseCase'; import { ProcessWalletTransactionUseCase } from '@gridpilot/payments/application/use-cases/ProcessWalletTransactionUseCase';
// Import concrete in-memory implementations // Import concrete in-memory implementations
import { InMemoryPaymentRepository } from 'adapters/payments/persistence/inmemory/InMemoryPaymentRepository'; import { InMemoryPaymentRepository } from '/payments/persistence/inmemory/InMemoryPaymentRepository';
import { InMemoryMembershipFeeRepository, InMemoryMemberPaymentRepository } from 'adapters/payments/persistence/inmemory/InMemoryMembershipFeeRepository'; import { InMemoryMembershipFeeRepository, InMemoryMemberPaymentRepository } from '/payments/persistence/inmemory/InMemoryMembershipFeeRepository';
import { InMemoryPrizeRepository } from 'adapters/payments/persistence/inmemory/InMemoryPrizeRepository'; import { InMemoryPrizeRepository } from '/payments/persistence/inmemory/InMemoryPrizeRepository';
import { InMemoryWalletRepository, InMemoryTransactionRepository } from 'adapters/payments/persistence/inmemory/InMemoryWalletRepository'; import { InMemoryWalletRepository, InMemoryTransactionRepository } from '/payments/persistence/inmemory/InMemoryWalletRepository';
import { ConsoleLogger } from 'adapters/logging/ConsoleLogger'; import { ConsoleLogger } from '/logging/ConsoleLogger';
// Repository injection tokens // Repository injection tokens
export const PAYMENT_REPOSITORY_TOKEN = 'IPaymentRepository'; export const PAYMENT_REPOSITORY_TOKEN = 'IPaymentRepository';

View File

@@ -7,9 +7,9 @@ import { IRaceRepository } from '@gridpilot/racing/domain/repositories/IRaceRepo
import { ILeagueRepository } from '@gridpilot/racing/domain/repositories/ILeagueRepository'; import { ILeagueRepository } from '@gridpilot/racing/domain/repositories/ILeagueRepository';
// Import concrete in-memory implementations // Import concrete in-memory implementations
import { InMemoryRaceRepository } from 'adapters/racing/persistence/inmemory/InMemoryRaceRepository'; import { InMemoryRaceRepository } from '/racing/persistence/inmemory/InMemoryRaceRepository';
import { InMemoryLeagueRepository } from 'adapters/racing/persistence/inmemory/InMemoryLeagueRepository'; import { InMemoryLeagueRepository } from '/racing/persistence/inmemory/InMemoryLeagueRepository';
import { ConsoleLogger } from 'adapters/logging/ConsoleLogger'; import { ConsoleLogger } from '/logging/ConsoleLogger';
// Import use cases // Import use cases
import { GetAllRacesUseCase } from '@gridpilot/racing/application/use-cases/GetAllRacesUseCase'; import { GetAllRacesUseCase } from '@gridpilot/racing/application/use-cases/GetAllRacesUseCase';

View File

@@ -21,15 +21,15 @@ import { GetSponsorSponsorshipsUseCase } from '@gridpilot/racing/application/use
import { GetEntitySponsorshipPricingUseCase } from '@gridpilot/racing/application/use-cases/GetEntitySponsorshipPricingUseCase'; import { GetEntitySponsorshipPricingUseCase } from '@gridpilot/racing/application/use-cases/GetEntitySponsorshipPricingUseCase';
// Import concrete in-memory implementations // Import concrete in-memory implementations
import { InMemorySponsorRepository } from 'adapters/racing/persistence/inmemory/InMemorySponsorRepository'; import { InMemorySponsorRepository } from '/racing/persistence/inmemory/InMemorySponsorRepository';
import { InMemorySeasonSponsorshipRepository } from 'adapters/racing/persistence/inmemory/InMemorySeasonSponsorshipRepository'; import { InMemorySeasonSponsorshipRepository } from '/racing/persistence/inmemory/InMemorySeasonSponsorshipRepository';
import { InMemorySeasonRepository } from 'adapters/racing/persistence/inmemory/InMemorySeasonRepository'; import { InMemorySeasonRepository } from '/racing/persistence/inmemory/InMemorySeasonRepository';
import { InMemoryLeagueRepository } from 'adapters/racing/persistence/inmemory/InMemoryLeagueRepository'; import { InMemoryLeagueRepository } from '/racing/persistence/inmemory/InMemoryLeagueRepository';
import { InMemoryLeagueMembershipRepository } from 'adapters/racing/persistence/inmemory/InMemoryLeagueMembershipRepository'; import { InMemoryLeagueMembershipRepository } from '/racing/persistence/inmemory/InMemoryLeagueMembershipRepository';
import { InMemoryRaceRepository } from 'adapters/racing/persistence/inmemory/InMemoryRaceRepository'; import { InMemoryRaceRepository } from '/racing/persistence/inmemory/InMemoryRaceRepository';
import { InMemorySponsorshipPricingRepository } from 'adapters/racing/persistence/inmemory/InMemorySponsorshipPricingRepository'; import { InMemorySponsorshipPricingRepository } from '/racing/persistence/inmemory/InMemorySponsorshipPricingRepository';
import { InMemorySponsorshipRequestRepository } from 'adapters/racing/persistence/inmemory/InMemorySponsorshipRequestRepository'; import { InMemorySponsorshipRequestRepository } from '/racing/persistence/inmemory/InMemorySponsorshipRequestRepository';
import { ConsoleLogger } from 'adapters/logging/ConsoleLogger'; import { ConsoleLogger } from '/logging/ConsoleLogger';
// Define injection tokens // Define injection tokens
export const SPONSOR_REPOSITORY_TOKEN = 'ISponsorRepository'; export const SPONSOR_REPOSITORY_TOKEN = 'ISponsorRepository';

View File

@@ -9,10 +9,10 @@ import { IImageServicePort } from '@gridpilot/racing/application/ports/IImageSer
import { Logger } from '@gridpilot/shared/application/Logger'; import { Logger } from '@gridpilot/shared/application/Logger';
// Import concrete in-memory implementations // Import concrete in-memory implementations
import { InMemoryTeamRepository } from 'adapters/racing/persistence/inmemory/InMemoryTeamRepository'; import { InMemoryTeamRepository } from '/racing/persistence/inmemory/InMemoryTeamRepository';
import { InMemoryTeamMembershipRepository } from 'adapters/racing/persistence/inmemory/InMemoryTeamMembershipRepository'; import { InMemoryTeamMembershipRepository } from '/racing/persistence/inmemory/InMemoryTeamMembershipRepository';
import { InMemoryDriverRepository } from 'adapters/racing/persistence/inmemory/InMemoryDriverRepository'; import { InMemoryDriverRepository } from '/racing/persistence/inmemory/InMemoryDriverRepository';
import { ConsoleLogger } from 'adapters/logging/ConsoleLogger'; import { ConsoleLogger } from '/logging/ConsoleLogger';
// Import use cases // Import use cases
import { GetAllTeamsUseCase } from '@gridpilot/racing/application/use-cases/GetAllTeamsUseCase'; import { GetAllTeamsUseCase } from '@gridpilot/racing/application/use-cases/GetAllTeamsUseCase';

View File

@@ -28,49 +28,49 @@
"types": ["node", "express", "jest"], "types": ["node", "express", "jest"],
"strictPropertyInitialization": false, "strictPropertyInitialization": false,
"paths": { "paths": {
"@gridpilot/shared/*": [ "@core/shared/*": [
"../../core/shared/*" "../../core/shared/*"
], ],
"@gridpilot/shared/application/*": [ "@core/shared/application/*": [
"../../core/shared/application/*" "../../core/shared/application/*"
], ],
"@gridpilot/payments/*": [ "@core/payments/*": [
"../../core/payments/*" "../../core/payments/*"
], ],
"@gridpilot/payments/application/*": [ "@core/payments/application/*": [
"../../core/payments/application/*" "../../core/payments/application/*"
], ],
"@gridpilot/payments/domain/*": [ "@core/payments/domain/*": [
"../../core/payments/domain/*" "../../core/payments/domain/*"
], ],
"@gridpilot/racing/*": [ "@core/racing/*": [
"../../core/racing/*" "../../core/racing/*"
], ],
"@gridpilot/league/*": [ "@core/league/*": [
"../../core/league/*" "../../core/league/*"
], ],
"@gridpilot/analytics/*": [ "@core/analytics/*": [
"../../core/analytics/*" "../../core/analytics/*"
], ],
"@gridpilot/analytics/domain/repositories/*": [ "@core/analytics/domain/repositories/*": [
"../../core/analytics/domain/repositories/*" "../../core/analytics/domain/repositories/*"
], ],
"@gridpilot/analytics/domain/entities/*": [ "@core/analytics/domain/entities/*": [
"../../core/analytics/domain/entities/*" "../../core/analytics/domain/entities/*"
], ],
"@gridpilot/core/identity/domain/repositories/*": [ "@core/core/identity/domain/repositories/*": [
"../../core/identity/domain/repositories/*" "../../core/identity/domain/repositories/*"
], ],
"@gridpilot/core/identity/domain/services/*": [ "@core/core/identity/domain/services/*": [
"../../core/identity/domain/services/*" "../../core/identity/domain/services/*"
], ],
"@gridpilot/core/identity/domain/entities/*": [ "@core/core/identity/domain/entities/*": [
"../../core/identity/domain/entities/*" "../../core/identity/domain/entities/*"
], ],
"@gridpilot/core/shared/logging/*": [ "@core/core/shared/logging/*": [
"../../core/shared/logging/*" "../../core/shared/logging/*"
], ],
"adapters/*": [ "@adapters/*": [
"../../adapters/*" "../../adapters/*"
], ],
"@nestjs/testing": [ "@nestjs/testing": [

View File

@@ -18,7 +18,7 @@ import { InitiateLoginUseCase } from '@gridpilot/automation/application/use-case
import { ClearSessionUseCase } from '@gridpilot/automation/application/use-cases/ClearSessionUseCase'; import { ClearSessionUseCase } from '@gridpilot/automation/application/use-cases/ClearSessionUseCase';
import { ConfirmCheckoutUseCase } from '@gridpilot/automation/application/use-cases/ConfirmCheckoutUseCase'; import { ConfirmCheckoutUseCase } from '@gridpilot/automation/application/use-cases/ConfirmCheckoutUseCase';
import { OverlaySyncService } from '@gridpilot/automation/application/services/OverlaySyncService'; import { OverlaySyncService } from '@gridpilot/automation/application/services/OverlaySyncService';
import type { IAutomationLifecycleEmitter } from '@gridpilot/automation/infrastructure/adapters/IAutomationLifecycleEmitter'; import type { IAutomationLifecycleEmitter } from '@gridpilot/automation/infrastructure//IAutomationLifecycleEmitter';
// Infrastructure // Infrastructure
import { InMemorySessionRepository } from '@gridpilot/automation/infrastructure/repositories/InMemorySessionRepository'; import { InMemorySessionRepository } from '@gridpilot/automation/infrastructure/repositories/InMemorySessionRepository';
@@ -27,11 +27,11 @@ import {
PlaywrightAutomationAdapter, PlaywrightAutomationAdapter,
AutomationAdapterMode, AutomationAdapterMode,
FixtureServer, FixtureServer,
} from '@gridpilot/automation/infrastructure/adapters/automation'; } from '@gridpilot/automation/infrastructure//automation';
import { MockAutomationEngineAdapter } from '@gridpilot/automation/infrastructure/adapters/automation/engine/MockAutomationEngineAdapter'; import { MockAutomationEngineAdapter } from '@gridpilot/automation/infrastructure//automation/engine/MockAutomationEngineAdapter';
import { AutomationEngineAdapter } from '@gridpilot/automation/infrastructure/adapters/automation/engine/AutomationEngineAdapter'; import { AutomationEngineAdapter } from '@gridpilot/automation/infrastructure//automation/engine/AutomationEngineAdapter';
import { ConsoleLogAdapter } from '@gridpilot/automation/infrastructure/adapters/logging/ConsoleLogAdapter'; import { ConsoleLogAdapter } from '@gridpilot/automation/infrastructure//logging/ConsoleLogAdapter';
import { NoOpLogAdapter } from '@gridpilot/automation/infrastructure/adapters/logging/NoOpLogAdapter'; import { NoOpLogAdapter } from '@gridpilot/automation/infrastructure//logging/NoOpLogAdapter';
import { import {
loadAutomationConfig, loadAutomationConfig,
getAutomationMode, getAutomationMode,

View File

@@ -1,7 +1,7 @@
import 'reflect-metadata'; import 'reflect-metadata';
import { configureDIContainer, resetDIContainer, getDIContainer, resolveSessionDataPath, resolveTemplatePath } from './di-config'; import { configureDIContainer, resetDIContainer, getDIContainer, resolveSessionDataPath, resolveTemplatePath } from './di-config';
import { DI_TOKENS } from './di-tokens'; import { DI_TOKENS } from './di-tokens';
import { PlaywrightAutomationAdapter, FixtureServer } from '@gridpilot/automation/infrastructure/adapters/automation'; import { PlaywrightAutomationAdapter, FixtureServer } from '@gridpilot/automation/infrastructure//automation';
import { StartAutomationSessionUseCase } from '@gridpilot/automation/application/use-cases/StartAutomationSessionUseCase'; import { StartAutomationSessionUseCase } from '@gridpilot/automation/application/use-cases/StartAutomationSessionUseCase';
import { CheckAuthenticationUseCase } from '@gridpilot/automation/application/use-cases/CheckAuthenticationUseCase'; import { CheckAuthenticationUseCase } from '@gridpilot/automation/application/use-cases/CheckAuthenticationUseCase';
import { InitiateLoginUseCase } from '@gridpilot/automation/application/use-cases/InitiateLoginUseCase'; import { InitiateLoginUseCase } from '@gridpilot/automation/application/use-cases/InitiateLoginUseCase';

View File

@@ -4,9 +4,9 @@ import { DIContainer } from './di-container';
import type { HostedSessionConfig } from 'core/automation/domain/types/HostedSessionConfig'; import type { HostedSessionConfig } from 'core/automation/domain/types/HostedSessionConfig';
import { StepId } from 'core/automation/domain/value-objects/StepId'; import { StepId } from 'core/automation/domain/value-objects/StepId';
import { AuthenticationState } from 'core/automation/domain/value-objects/AuthenticationState'; import { AuthenticationState } from 'core/automation/domain/value-objects/AuthenticationState';
import { ElectronCheckoutConfirmationAdapter } from 'core/automation/infrastructure/adapters/ipc/ElectronCheckoutConfirmationAdapter'; import { ElectronCheckoutConfirmationAdapter } from 'core/automation/infrastructure//ipc/ElectronCheckoutConfirmationAdapter';
import type { OverlayAction } from 'core/automation/application/ports/OverlaySyncPort'; import type { OverlayAction } from 'core/automation/application/ports/OverlaySyncPort';
import type { IAutomationLifecycleEmitter } from 'core/automation/infrastructure/adapters/IAutomationLifecycleEmitter'; import type { IAutomationLifecycleEmitter } from 'core/automation/infrastructure//IAutomationLifecycleEmitter';
let progressMonitorInterval: NodeJS.Timeout | null = null; let progressMonitorInterval: NodeJS.Timeout | null = null;
let lifecycleSubscribed = false; let lifecycleSubscribed = false;
@@ -335,7 +335,7 @@ export function setupIpcHandlers(mainWindow: BrowserWindow): void {
loader.setDevelopmentMode(mode); loader.setDevelopmentMode(mode);
// Ensure runtime automation wiring reflects the new browser mode // Ensure runtime automation wiring reflects the new browser mode
if ('refreshBrowserAutomation' in container) { if ('refreshBrowserAutomation' in container) {
// Call method to refresh adapters/use-cases that depend on browser mode // Call method to refresh /use-cases that depend on browser mode
container.refreshBrowserAutomation(); container.refreshBrowserAutomation();
} }
logger.info('Browser mode updated', { mode }); logger.info('Browser mode updated', { mode });

View File

@@ -1,9 +1,22 @@
{ {
"extends": "next/core-web-vitals", "extends": "next/core-web-vitals",
"plugins": ["boundaries"],
"rules": { "rules": {
"react/no-unescaped-entities": "off", "react/no-unescaped-entities": "off",
"@next/next/no-img-element": "warn", "@next/next/no-img-element": "warn",
"react-hooks/exhaustive-deps": "warn", "react-hooks/exhaustive-deps": "warn",
"@typescript-eslint/no-explicit-any": "error" "@typescript-eslint/no-explicit-any": "error",
"boundaries/element-types": [
2,
{
"default": "disallow",
"rules": [
{
"from": ["website"],
"allow": ["website"]
}
]
}
]
} }
} }

View File

@@ -18,20 +18,20 @@
"@/lib/*": ["./lib/*"], "@/lib/*": ["./lib/*"],
"@/components/*": ["./components/*"], "@/components/*": ["./components/*"],
"@/app/*": ["./app/*"], "@/app/*": ["./app/*"],
"@gridpilot/identity": ["../../core/identity/index.ts"], "@core/identity": ["../../core/identity/index.ts"],
"@gridpilot/identity/*": ["../../core/identity/*"], "@core/identity/*": ["../../core/identity/*"],
"@gridpilot/racing": ["../../core/racing/index.ts"], "@core/racing": ["../../core/racing/index.ts"],
"@gridpilot/racing/*": ["../../core/racing/*"], "@core/racing/*": ["../../core/racing/*"],
"@gridpilot/social": ["../../core/social/index.ts"], "@core/social": ["../../core/social/index.ts"],
"@gridpilot/social/*": ["../../core/social/*"], "@core/social/*": ["../../core/social/*"],
"@gridpilot/testing-support": ["../../core/testing-support/index.ts"], "@core/testing-support": ["../../core/testing-support/index.ts"],
"@gridpilot/testing-support/*": ["../../core/testing-support/*"], "@core/testing-support/*": ["../../core/testing-support/*"],
"@gridpilot/media": ["../../core/media/index.ts"], "@core/media": ["../../core/media/index.ts"],
"@gridpilot/media/*": ["../../core/media/*"], "@core/media/*": ["../../core/media/*"],
"@gridpilot/shared/logging": ["../../core/shared/logging"], "@core/shared/logging": ["../../core/shared/logging"],
"@gridpilot/shared/*": ["../../core/shared/*"], "@core/shared/*": ["../../core/shared/*"],
"@gridpilot/core/*": ["../../core/*"], "@core/core/*": ["../../core/*"],
"@gridpilot/api/*": ["../../apps/api/src/*"] "@core/api/*": ["../../apps/api/src/*"]
} }
}, },
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],

View File

@@ -7,5 +7,5 @@ export { InMemoryNotificationRepository } from './repositories/InMemoryNotificat
export { InMemoryNotificationPreferenceRepository } from './repositories/InMemoryNotificationPreferenceRepository'; export { InMemoryNotificationPreferenceRepository } from './repositories/InMemoryNotificationPreferenceRepository';
// Adapters // Adapters
export { InAppNotificationAdapter } from './adapters/InAppNotificationAdapter'; export { InAppNotificationAdapter } from './/InAppNotificationAdapter';
export { NotificationGatewayRegistry } from './adapters/NotificationGatewayRegistry'; export { NotificationGatewayRegistry } from './/NotificationGatewayRegistry';

View File

@@ -1,7 +1,7 @@
import { describe, expect, test } from 'vitest' import { describe, expect, test } from 'vitest'
import { OverlayAction, ActionAck } from '../../../../core/automation/application/ports/IOverlaySyncPort' import { OverlayAction, ActionAck } from '../../../../core/automation/application/ports/IOverlaySyncPort'
import { IAutomationEventPublisher, AutomationEvent } from '../../../../core/automation/application/ports/IAutomationEventPublisher' import { IAutomationEventPublisher, AutomationEvent } from '../../../../core/automation/application/ports/IAutomationEventPublisher'
import { IAutomationLifecycleEmitter, LifecycleCallback } from '../../../../core/automation/infrastructure/adapters/IAutomationLifecycleEmitter' import { IAutomationLifecycleEmitter, LifecycleCallback } from '../../../../core/automation/infrastructure//IAutomationLifecycleEmitter'
import { OverlaySyncService } from '../../../../core/automation/application/services/OverlaySyncService' import { OverlaySyncService } from '../../../../core/automation/application/services/OverlaySyncService'
class MockLifecycleEmitter implements IAutomationLifecycleEmitter { class MockLifecycleEmitter implements IAutomationLifecycleEmitter {

View File

@@ -1,6 +1,6 @@
import { describe, expect, test } from 'vitest' import { describe, expect, test } from 'vitest'
import { OverlayAction } from '../../../../core/automation/application/ports/OverlaySyncPort' import { OverlayAction } from '../../../../core/automation/application/ports/OverlaySyncPort'
import { IAutomationLifecycleEmitter, LifecycleCallback } from '../../../../core/automation/infrastructure/adapters/IAutomationLifecycleEmitter' import { IAutomationLifecycleEmitter, LifecycleCallback } from '../../../../core/automation/infrastructure//IAutomationLifecycleEmitter'
import { OverlaySyncService } from '../../../../core/automation/application/services/OverlaySyncService' import { OverlaySyncService } from '../../../../core/automation/application/services/OverlaySyncService'
class MockLifecycleEmitter implements IAutomationLifecycleEmitter { class MockLifecycleEmitter implements IAutomationLifecycleEmitter {

View File

@@ -3,9 +3,9 @@ import { StepId } from '@gridpilot/automation/domain/value-objects/StepId';
import { import {
FixtureServer, FixtureServer,
PlaywrightAutomationAdapter, PlaywrightAutomationAdapter,
} from 'core/automation/infrastructure/adapters/automation'; } from 'core/automation/infrastructure//automation';
import { IRACING_SELECTORS } from 'core/automation/infrastructure/adapters/automation/dom/IRacingSelectors'; import { IRACING_SELECTORS } from 'core/automation/infrastructure//automation/dom/IRacingSelectors';
import { PinoLogAdapter } from 'core/automation/infrastructure/adapters/logging/PinoLogAdapter'; import { PinoLogAdapter } from 'core/automation/infrastructure//logging/PinoLogAdapter';
describe('Real Playwright hosted-session smoke (fixtures, steps 27)', () => { describe('Real Playwright hosted-session smoke (fixtures, steps 27)', () => {
let server: FixtureServer; let server: FixtureServer;

View File

@@ -2,7 +2,7 @@ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { DIContainer } from '../../../apps/companion/main/di-container'; import { DIContainer } from '../../../apps/companion/main/di-container';
import { StepId } from '@gridpilot/automation/domain/value-objects/StepId'; import { StepId } from '@gridpilot/automation/domain/value-objects/StepId';
import type { HostedSessionConfig } from '@gridpilot/automation/domain/types/HostedSessionConfig'; import type { HostedSessionConfig } from '@gridpilot/automation/domain/types/HostedSessionConfig';
import { PlaywrightAutomationAdapter } from 'core/automation/infrastructure/adapters/automation'; import { PlaywrightAutomationAdapter } from 'core/automation/infrastructure//automation';
describe('Companion UI - hosted workflow via fixture-backed real stack', () => { describe('Companion UI - hosted workflow via fixture-backed real stack', () => {
let container: DIContainer; let container: DIContainer;

View File

@@ -2,12 +2,12 @@ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { StepId } from '@gridpilot/automation/domain/value-objects/StepId'; import { StepId } from '@gridpilot/automation/domain/value-objects/StepId';
import { import {
PlaywrightAutomationAdapter, PlaywrightAutomationAdapter,
} from 'core/automation/infrastructure/adapters/automation'; } from 'core/automation/infrastructure//automation';
import { import {
IRACING_SELECTORS, IRACING_SELECTORS,
IRACING_TIMEOUTS, IRACING_TIMEOUTS,
} from 'core/automation/infrastructure/adapters/automation/dom/IRacingSelectors'; } from 'core/automation/infrastructure//automation/dom/IRacingSelectors';
import { PinoLogAdapter } from 'core/automation/infrastructure/adapters/logging/PinoLogAdapter'; import { PinoLogAdapter } from 'core/automation/infrastructure//logging/PinoLogAdapter';
const shouldRun = process.env.HOSTED_REAL_E2E === '1'; const shouldRun = process.env.HOSTED_REAL_E2E === '1';
const describeMaybe = shouldRun ? describe : describe.skip; const describeMaybe = shouldRun ? describe : describe.skip;

View File

@@ -2,12 +2,12 @@ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { StepId } from '@gridpilot/automation/domain/value-objects/StepId'; import { StepId } from '@gridpilot/automation/domain/value-objects/StepId';
import { import {
PlaywrightAutomationAdapter, PlaywrightAutomationAdapter,
} from 'core/automation/infrastructure/adapters/automation'; } from 'core/automation/infrastructure//automation';
import { import {
IRACING_SELECTORS, IRACING_SELECTORS,
IRACING_TIMEOUTS, IRACING_TIMEOUTS,
} from 'core/automation/infrastructure/adapters/automation/dom/IRacingSelectors'; } from 'core/automation/infrastructure//automation/dom/IRacingSelectors';
import { PinoLogAdapter } from 'core/automation/infrastructure/adapters/logging/PinoLogAdapter'; import { PinoLogAdapter } from 'core/automation/infrastructure//logging/PinoLogAdapter';
const shouldRun = process.env.HOSTED_REAL_E2E === '1'; const shouldRun = process.env.HOSTED_REAL_E2E === '1';

View File

@@ -4,12 +4,12 @@ import path from 'path';
import { StepId } from '@gridpilot/automation/domain/value-objects/StepId'; import { StepId } from '@gridpilot/automation/domain/value-objects/StepId';
import { import {
PlaywrightAutomationAdapter, PlaywrightAutomationAdapter,
} from 'core/automation/infrastructure/adapters/automation'; } from 'core/automation/infrastructure//automation';
import { import {
IRACING_SELECTORS, IRACING_SELECTORS,
IRACING_TIMEOUTS, IRACING_TIMEOUTS,
} from 'core/automation/infrastructure/adapters/automation/dom/IRacingSelectors'; } from 'core/automation/infrastructure//automation/dom/IRacingSelectors';
import { PinoLogAdapter } from 'core/automation/infrastructure/adapters/logging/PinoLogAdapter'; import { PinoLogAdapter } from 'core/automation/infrastructure//logging/PinoLogAdapter';
const shouldRun = process.env.HOSTED_REAL_E2E === '1'; const shouldRun = process.env.HOSTED_REAL_E2E === '1';
const describeMaybe = shouldRun ? describe : describe.skip; const describeMaybe = shouldRun ? describe : describe.skip;

View File

@@ -1,7 +1,7 @@
import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import type { StepHarness } from '../support/StepHarness'; import type { StepHarness } from '../support/StepHarness';
import { createStepHarness } from '../support/StepHarness'; import { createStepHarness } from '../support/StepHarness';
import { IRACING_SELECTORS } from 'core/automation/infrastructure/adapters/automation/dom/IRacingSelectors'; import { IRACING_SELECTORS } from 'core/automation/infrastructure//automation/dom/IRacingSelectors';
describe('Step 2 create race', () => { describe('Step 2 create race', () => {
let harness: StepHarness; let harness: StepHarness;

View File

@@ -1,7 +1,7 @@
import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import type { StepHarness } from '../support/StepHarness'; import type { StepHarness } from '../support/StepHarness';
import { createStepHarness } from '../support/StepHarness'; import { createStepHarness } from '../support/StepHarness';
import { IRACING_SELECTORS } from 'core/automation/infrastructure/adapters/automation/dom/IRacingSelectors'; import { IRACING_SELECTORS } from 'core/automation/infrastructure//automation/dom/IRacingSelectors';
describe('Step 3 race information', () => { describe('Step 3 race information', () => {
let harness: StepHarness; let harness: StepHarness;

View File

@@ -1,7 +1,7 @@
import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import type { StepHarness } from '../support/StepHarness'; import type { StepHarness } from '../support/StepHarness';
import { createStepHarness } from '../support/StepHarness'; import { createStepHarness } from '../support/StepHarness';
import { IRACING_SELECTORS } from 'core/automation/infrastructure/adapters/automation/dom/IRacingSelectors'; import { IRACING_SELECTORS } from 'core/automation/infrastructure//automation/dom/IRacingSelectors';
describe('Step 4 server details', () => { describe('Step 4 server details', () => {
let harness: StepHarness; let harness: StepHarness;

View File

@@ -1,7 +1,7 @@
import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import type { StepHarness } from '../support/StepHarness'; import type { StepHarness } from '../support/StepHarness';
import { createStepHarness } from '../support/StepHarness'; import { createStepHarness } from '../support/StepHarness';
import { IRACING_SELECTORS } from 'core/automation/infrastructure/adapters/automation/dom/IRacingSelectors'; import { IRACING_SELECTORS } from 'core/automation/infrastructure//automation/dom/IRacingSelectors';
describe('Step 5 set admins', () => { describe('Step 5 set admins', () => {
let harness: StepHarness; let harness: StepHarness;

View File

@@ -1,7 +1,7 @@
import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import type { StepHarness } from '../support/StepHarness'; import type { StepHarness } from '../support/StepHarness';
import { createStepHarness } from '../support/StepHarness'; import { createStepHarness } from '../support/StepHarness';
import { IRACING_SELECTORS } from 'core/automation/infrastructure/adapters/automation/dom/IRacingSelectors'; import { IRACING_SELECTORS } from 'core/automation/infrastructure//automation/dom/IRacingSelectors';
describe('Step 6 admins', () => { describe('Step 6 admins', () => {
let harness: StepHarness; let harness: StepHarness;

View File

@@ -1,7 +1,7 @@
import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import type { StepHarness } from '../support/StepHarness'; import type { StepHarness } from '../support/StepHarness';
import { createStepHarness } from '../support/StepHarness'; import { createStepHarness } from '../support/StepHarness';
import { IRACING_SELECTORS } from 'core/automation/infrastructure/adapters/automation/dom/IRacingSelectors'; import { IRACING_SELECTORS } from 'core/automation/infrastructure//automation/dom/IRacingSelectors';
describe('Step 7 time limits', () => { describe('Step 7 time limits', () => {
let harness: StepHarness; let harness: StepHarness;

View File

@@ -1,7 +1,7 @@
import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import type { StepHarness } from '../support/StepHarness'; import type { StepHarness } from '../support/StepHarness';
import { createStepHarness } from '../support/StepHarness'; import { createStepHarness } from '../support/StepHarness';
import { IRACING_SELECTORS } from 'core/automation/infrastructure/adapters/automation/dom/IRacingSelectors'; import { IRACING_SELECTORS } from 'core/automation/infrastructure//automation/dom/IRacingSelectors';
describe('Step 8 cars', () => { describe('Step 8 cars', () => {
let harness: StepHarness; let harness: StepHarness;

View File

@@ -1,7 +1,7 @@
import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import type { StepHarness } from '../support/StepHarness'; import type { StepHarness } from '../support/StepHarness';
import { createStepHarness } from '../support/StepHarness'; import { createStepHarness } from '../support/StepHarness';
import { IRACING_SELECTORS } from 'core/automation/infrastructure/adapters/automation/dom/IRacingSelectors'; import { IRACING_SELECTORS } from 'core/automation/infrastructure//automation/dom/IRacingSelectors';
describe('Step 13 track options', () => { describe('Step 13 track options', () => {
let harness: StepHarness; let harness: StepHarness;

View File

@@ -1,7 +1,7 @@
import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import type { StepHarness } from '../support/StepHarness'; import type { StepHarness } from '../support/StepHarness';
import { createStepHarness } from '../support/StepHarness'; import { createStepHarness } from '../support/StepHarness';
import { IRACING_SELECTORS } from 'core/automation/infrastructure/adapters/automation/dom/IRacingSelectors'; import { IRACING_SELECTORS } from 'core/automation/infrastructure//automation/dom/IRacingSelectors';
describe('Step 14 time of day', () => { describe('Step 14 time of day', () => {
let harness: StepHarness; let harness: StepHarness;

View File

@@ -1,7 +1,7 @@
import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import type { StepHarness } from '../support/StepHarness'; import type { StepHarness } from '../support/StepHarness';
import { createStepHarness } from '../support/StepHarness'; import { createStepHarness } from '../support/StepHarness';
import { IRACING_SELECTORS } from 'core/automation/infrastructure/adapters/automation/dom/IRacingSelectors'; import { IRACING_SELECTORS } from 'core/automation/infrastructure//automation/dom/IRacingSelectors';
describe('Step 15 weather', () => { describe('Step 15 weather', () => {
let harness: StepHarness; let harness: StepHarness;

View File

@@ -1,5 +1,5 @@
import { StepId } from '@gridpilot/automation/domain/value-objects/StepId'; import { StepId } from '@gridpilot/automation/domain/value-objects/StepId';
import type { PlaywrightAutomationAdapter } from 'core/automation/infrastructure/adapters/automation'; import type { PlaywrightAutomationAdapter } from 'core/automation/infrastructure//automation';
import type { AutomationResult } from 'core/automation/application/ports/AutomationResults'; import type { AutomationResult } from 'core/automation/application/ports/AutomationResults';
export function assertAutoNavigationConfig(config: Record<string, unknown>): void { export function assertAutoNavigationConfig(config: Record<string, unknown>): void {

View File

@@ -3,8 +3,8 @@ import { StepId } from '@gridpilot/automation/domain/value-objects/StepId';
import { import {
PlaywrightAutomationAdapter, PlaywrightAutomationAdapter,
FixtureServer, FixtureServer,
} from 'core/automation/infrastructure/adapters/automation'; } from 'core/automation/infrastructure//automation';
import { PinoLogAdapter } from 'core/automation/infrastructure/adapters/logging/PinoLogAdapter'; import { PinoLogAdapter } from 'core/automation/infrastructure//logging/PinoLogAdapter';
export interface StepHarness { export interface StepHarness {
server: FixtureServer; server: FixtureServer;

View File

@@ -2,9 +2,9 @@ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { import {
PlaywrightAutomationAdapter, PlaywrightAutomationAdapter,
FixtureServer, FixtureServer,
} from 'core/automation/infrastructure/adapters/automation'; } from 'core/automation/infrastructure//automation';
import { StepId } from '@gridpilot/automation/domain/value-objects/StepId'; import { StepId } from '@gridpilot/automation/domain/value-objects/StepId';
import { PinoLogAdapter } from 'core/automation/infrastructure/adapters/logging/PinoLogAdapter'; import { PinoLogAdapter } from 'core/automation/infrastructure//logging/PinoLogAdapter';
import { executeStepWithAutoNavigationGuard } from '../support/AutoNavGuard'; import { executeStepWithAutoNavigationGuard } from '../support/AutoNavGuard';
describe('Hosted validator guards (fixture-backed, real stack)', () => { describe('Hosted validator guards (fixture-backed, real stack)', () => {

View File

@@ -2,10 +2,10 @@ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { import {
PlaywrightAutomationAdapter, PlaywrightAutomationAdapter,
FixtureServer, FixtureServer,
} from 'core/automation/infrastructure/adapters/automation'; } from 'core/automation/infrastructure//automation';
import { StepId } from '@gridpilot/automation/domain/value-objects/StepId'; import { StepId } from '@gridpilot/automation/domain/value-objects/StepId';
import { PinoLogAdapter } from 'core/automation/infrastructure/adapters/logging/PinoLogAdapter'; import { PinoLogAdapter } from 'core/automation/infrastructure//logging/PinoLogAdapter';
import { IRACING_SELECTORS } from 'core/automation/infrastructure/adapters/automation/dom/IRacingSelectors'; import { IRACING_SELECTORS } from 'core/automation/infrastructure//automation/dom/IRacingSelectors';
import { executeStepWithAutoNavigationGuard } from '../support/AutoNavGuard'; import { executeStepWithAutoNavigationGuard } from '../support/AutoNavGuard';
describe('Workflow hosted session autonav slice (fixture-backed, real stack)', () => { describe('Workflow hosted session autonav slice (fixture-backed, real stack)', () => {

View File

@@ -2,12 +2,12 @@ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { import {
PlaywrightAutomationAdapter, PlaywrightAutomationAdapter,
FixtureServer, FixtureServer,
} from 'core/automation/infrastructure/adapters/automation'; } from 'core/automation/infrastructure//automation';
import { InMemorySessionRepository } from 'core/automation/infrastructure/repositories/InMemorySessionRepository'; import { InMemorySessionRepository } from 'core/automation/infrastructure/repositories/InMemorySessionRepository';
import { AutomationEngineAdapter } from 'core/automation/infrastructure/adapters/automation/engine/AutomationEngineAdapter'; import { AutomationEngineAdapter } from 'core/automation/infrastructure//automation/engine/AutomationEngineAdapter';
import { StartAutomationSessionUseCase } from 'core/automation/application/use-cases/StartAutomationSessionUseCase'; import { StartAutomationSessionUseCase } from 'core/automation/application/use-cases/StartAutomationSessionUseCase';
import { StepId } from '@gridpilot/automation/domain/value-objects/StepId'; import { StepId } from '@gridpilot/automation/domain/value-objects/StepId';
import { PinoLogAdapter } from 'core/automation/infrastructure/adapters/logging/PinoLogAdapter'; import { PinoLogAdapter } from 'core/automation/infrastructure//logging/PinoLogAdapter';
describe('Workflow hosted session end-to-end (fixture-backed, real stack)', () => { describe('Workflow hosted session end-to-end (fixture-backed, real stack)', () => {
let server: FixtureServer; let server: FixtureServer;

View File

@@ -2,10 +2,10 @@ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { import {
PlaywrightAutomationAdapter, PlaywrightAutomationAdapter,
FixtureServer, FixtureServer,
} from 'core/automation/infrastructure/adapters/automation'; } from 'core/automation/infrastructure//automation';
import { StepId } from '@gridpilot/automation/domain/value-objects/StepId'; import { StepId } from '@gridpilot/automation/domain/value-objects/StepId';
import { IRACING_SELECTORS } from 'core/automation/infrastructure/adapters/automation/dom/IRacingSelectors'; import { IRACING_SELECTORS } from 'core/automation/infrastructure//automation/dom/IRacingSelectors';
import { PinoLogAdapter } from 'core/automation/infrastructure/adapters/logging/PinoLogAdapter'; import { PinoLogAdapter } from 'core/automation/infrastructure//logging/PinoLogAdapter';
describe('Workflow steps 79 cars flow (fixture-backed, real stack)', () => { describe('Workflow steps 79 cars flow (fixture-backed, real stack)', () => {
let adapter: PlaywrightAutomationAdapter; let adapter: PlaywrightAutomationAdapter;

View File

@@ -1,6 +1,6 @@
import { describe, test, expect, beforeEach, vi } from 'vitest'; import { describe, test, expect, beforeEach, vi } from 'vitest';
import type { Page } from 'playwright'; import type { Page } from 'playwright';
import { AuthenticationGuard } from '@gridpilot/automation/infrastructure/adapters/automation/auth/AuthenticationGuard'; import { AuthenticationGuard } from '@gridpilot/automation/infrastructure//automation/auth/AuthenticationGuard';
describe('AuthenticationGuard', () => { describe('AuthenticationGuard', () => {
let mockPage: Page; let mockPage: Page;

View File

@@ -9,7 +9,7 @@ vi.mock('electron', () => ({
}, },
})); }));
import { ElectronCheckoutConfirmationAdapter } from '@gridpilot/automation/infrastructure/adapters/ipc/ElectronCheckoutConfirmationAdapter'; import { ElectronCheckoutConfirmationAdapter } from '@gridpilot/automation/infrastructure//ipc/ElectronCheckoutConfirmationAdapter';
import { CheckoutPrice } from '@gridpilot/automation/domain/value-objects/CheckoutPrice'; import { CheckoutPrice } from '@gridpilot/automation/domain/value-objects/CheckoutPrice';
import { CheckoutState } from '@gridpilot/automation/domain/value-objects/CheckoutState'; import { CheckoutState } from '@gridpilot/automation/domain/value-objects/CheckoutState';
import { ipcMain } from 'electron'; import { ipcMain } from 'electron';

View File

@@ -1,9 +1,9 @@
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import type { Page, BrowserContext } from 'playwright'; import type { Page, BrowserContext } from 'playwright';
import { PlaywrightAuthSessionService } from '../../../../core/automation/infrastructure/adapters/automation/auth/PlaywrightAuthSessionService'; import { PlaywrightAuthSessionService } from '../../../../core/automation/infrastructure//automation/auth/PlaywrightAuthSessionService';
import type { PlaywrightBrowserSession } from '../../../../core/automation/infrastructure/adapters/automation/core/PlaywrightBrowserSession'; import type { PlaywrightBrowserSession } from '../../../../core/automation/infrastructure//automation/core/PlaywrightBrowserSession';
import type { SessionCookieStore } from '../../../../core/automation/infrastructure/adapters/automation/auth/SessionCookieStore'; import type { SessionCookieStore } from '../../../../core/automation/infrastructure//automation/auth/SessionCookieStore';
import type { IPlaywrightAuthFlow } from '../../../../core/automation/infrastructure/adapters/automation/auth/PlaywrightAuthFlow'; import type { IPlaywrightAuthFlow } from '../../../../core/automation/infrastructure//automation/auth/PlaywrightAuthFlow';
import type { LoggerPort as Logger } from '../../../../core/automation/application/ports/LoggerPort'; import type { LoggerPort as Logger } from '../../../../core/automation/application/ports/LoggerPort';
import { AuthenticationState } from '@gridpilot/automation/domain/value-objects/AuthenticationState'; import { AuthenticationState } from '@gridpilot/automation/domain/value-objects/AuthenticationState';
import { Result } from '../../../../core/shared/result/Result'; import { Result } from '../../../../core/shared/result/Result';

View File

@@ -1,13 +1,13 @@
import { describe, it, expect, vi } from 'vitest'; import { describe, it, expect, vi } from 'vitest';
import type { Page, Locator } from 'playwright'; import type { Page, Locator } from 'playwright';
import { PlaywrightAuthSessionService } from '../../../../core/automation/infrastructure/adapters/automation/auth/PlaywrightAuthSessionService'; import { PlaywrightAuthSessionService } from '../../../../core/automation/infrastructure//automation/auth/PlaywrightAuthSessionService';
import { AuthenticationState } from '@gridpilot/automation/domain/value-objects/AuthenticationState'; import { AuthenticationState } from '@gridpilot/automation/domain/value-objects/AuthenticationState';
import { BrowserAuthenticationState } from '@gridpilot/automation/domain/value-objects/BrowserAuthenticationState'; import { BrowserAuthenticationState } from '@gridpilot/automation/domain/value-objects/BrowserAuthenticationState';
import type { LoggerPort as Logger } from '../../../../core/automation/application/ports/LoggerPort'; import type { LoggerPort as Logger } from '../../../../core/automation/application/ports/LoggerPort';
import type { Result } from '../../../../core/shared/result/Result'; import type { Result } from '../../../../core/shared/result/Result';
import type { PlaywrightBrowserSession } from '../../../../core/automation/infrastructure/adapters/automation/core/PlaywrightBrowserSession'; import type { PlaywrightBrowserSession } from '../../../../core/automation/infrastructure//automation/core/PlaywrightBrowserSession';
import type { SessionCookieStore } from '../../../../core/automation/infrastructure/adapters/automation/auth/SessionCookieStore'; import type { SessionCookieStore } from '../../../../core/automation/infrastructure//automation/auth/SessionCookieStore';
import type { IPlaywrightAuthFlow } from '../../../../core/automation/infrastructure/adapters/automation/auth/PlaywrightAuthFlow'; import type { IPlaywrightAuthFlow } from '../../../../core/automation/infrastructure//automation/auth/PlaywrightAuthFlow';
describe('PlaywrightAuthSessionService.verifyPageAuthentication', () => { describe('PlaywrightAuthSessionService.verifyPageAuthentication', () => {
function createService(deps: { function createService(deps: {

View File

@@ -1,5 +1,5 @@
import { describe, test, expect, beforeEach } from 'vitest'; import { describe, test, expect, beforeEach } from 'vitest';
import { SessionCookieStore } from '@gridpilot/automation/infrastructure/adapters/automation/auth/SessionCookieStore'; import { SessionCookieStore } from '@gridpilot/automation/infrastructure//automation/auth/SessionCookieStore';
import type { Cookie } from 'playwright'; import type { Cookie } from 'playwright';
const logger = console as any; const logger = console as any;

View File

@@ -4,9 +4,9 @@ import { configureDIContainer, resetDIContainer } from "../../../apps/companion/
import { DI_TOKENS } from "../../../apps/companion/main/di-tokens"; import { DI_TOKENS } from "../../../apps/companion/main/di-tokens";
import { OverlaySyncService } from "@gridpilot/automation/application/services/OverlaySyncService"; import { OverlaySyncService } from "@gridpilot/automation/application/services/OverlaySyncService";
import { LoggerPort } from "@gridpilot/automation/application/ports/LoggerPort"; import { LoggerPort } from "@gridpilot/automation/application/ports/LoggerPort";
import { IAutomationLifecycleEmitter, LifecycleCallback } from "@gridpilot/automation/infrastructure/adapters/IAutomationLifecycleEmitter"; import { IAutomationLifecycleEmitter, LifecycleCallback } from "@gridpilot/automation/infrastructure//IAutomationLifecycleEmitter";
import { AutomationEventPublisherPort, AutomationEvent } from "@gridpilot/automation/application/ports/AutomationEventPublisherPort"; import { AutomationEventPublisherPort, AutomationEvent } from "@gridpilot/automation/application/ports/AutomationEventPublisherPort";
import { ConsoleLogAdapter } from "@gridpilot/automation/infrastructure/adapters/logging/ConsoleLogAdapter"; import { ConsoleLogAdapter } from "@gridpilot/automation/infrastructure//logging/ConsoleLogAdapter";
import { describe, it, expect, beforeEach, afterEach, vi, SpyInstance } from 'vitest'; import { describe, it, expect, beforeEach, afterEach, vi, SpyInstance } from 'vitest';
describe("OverlaySyncService Integration with ConsoleLogAdapter", () => { describe("OverlaySyncService Integration with ConsoleLogAdapter", () => {

View File

@@ -87,7 +87,7 @@ describe('Browser Mode Integration - GREEN Phase', () => {
}); });
const { PlaywrightAutomationAdapter } = await import( const { PlaywrightAutomationAdapter } = await import(
'core/automation/infrastructure/adapters/automation' 'core/automation/infrastructure//automation'
); );
adapter = new PlaywrightAutomationAdapter({ adapter = new PlaywrightAutomationAdapter({
@@ -111,7 +111,7 @@ describe('Browser Mode Integration - GREEN Phase', () => {
}); });
const { PlaywrightAutomationAdapter } = await import( const { PlaywrightAutomationAdapter } = await import(
'core/automation/infrastructure/adapters/automation' 'core/automation/infrastructure//automation'
); );
adapter = new PlaywrightAutomationAdapter({ adapter = new PlaywrightAutomationAdapter({
@@ -135,7 +135,7 @@ describe('Browser Mode Integration - GREEN Phase', () => {
}); });
const { PlaywrightAutomationAdapter } = await import( const { PlaywrightAutomationAdapter } = await import(
'core/automation/infrastructure/adapters/automation' 'core/automation/infrastructure//automation'
); );
adapter = new PlaywrightAutomationAdapter({ adapter = new PlaywrightAutomationAdapter({
@@ -164,7 +164,7 @@ describe('Browser Mode Integration - GREEN Phase', () => {
}); });
const { PlaywrightAutomationAdapter } = await import( const { PlaywrightAutomationAdapter } = await import(
'core/automation/infrastructure/adapters/automation' 'core/automation/infrastructure//automation'
); );
adapter = new PlaywrightAutomationAdapter({ adapter = new PlaywrightAutomationAdapter({
@@ -185,7 +185,7 @@ describe('Browser Mode Integration - GREEN Phase', () => {
}); });
const { PlaywrightAutomationAdapter } = await import( const { PlaywrightAutomationAdapter } = await import(
'core/automation/infrastructure/adapters/automation' 'core/automation/infrastructure//automation'
); );
adapter = new PlaywrightAutomationAdapter({ adapter = new PlaywrightAutomationAdapter({
@@ -228,7 +228,7 @@ describe('Browser Mode Integration - GREEN Phase', () => {
}; };
const { PlaywrightAutomationAdapter } = await import( const { PlaywrightAutomationAdapter } = await import(
'core/automation/infrastructure/adapters/automation' 'core/automation/infrastructure//automation'
); );
adapter = new PlaywrightAutomationAdapter( adapter = new PlaywrightAutomationAdapter(
@@ -259,7 +259,7 @@ describe('Browser Mode Integration - GREEN Phase', () => {
}); });
const { PlaywrightAutomationAdapter } = await import( const { PlaywrightAutomationAdapter } = await import(
'core/automation/infrastructure/adapters/automation' 'core/automation/infrastructure//automation'
); );
const userDataDir = path.join(process.cwd(), 'test-browser-data'); const userDataDir = path.join(process.cwd(), 'test-browser-data');
@@ -290,7 +290,7 @@ describe('Browser Mode Integration - GREEN Phase', () => {
configurable: true configurable: true
}); });
const { PlaywrightAutomationAdapter } = await import( const { PlaywrightAutomationAdapter } = await import(
'core/automation/infrastructure/adapters/automation' 'core/automation/infrastructure//automation'
); );
const { BrowserModeConfigLoader } = await import( const { BrowserModeConfigLoader } = await import(
'../../../core/automation/infrastructure/config/BrowserModeConfig' '../../../core/automation/infrastructure/config/BrowserModeConfig'

View File

@@ -1,6 +1,6 @@
import { describe, it, expect, beforeEach, vi } from 'vitest'; import { describe, it, expect, beforeEach, vi } from 'vitest';
import { Result } from '../../../core/shared/result/Result'; import { Result } from '../../../core/shared/result/Result';
import { CheckoutPriceExtractor } from '../../../core/automation/infrastructure/adapters/automation/CheckoutPriceExtractor'; import { CheckoutPriceExtractor } from '../../../core/automation/infrastructure//automation/CheckoutPriceExtractor';
import { CheckoutStateEnum } from '@gridpilot/automation/domain/value-objects/CheckoutState'; import { CheckoutStateEnum } from '@gridpilot/automation/domain/value-objects/CheckoutState';
/** /**

View File

@@ -3,7 +3,7 @@
*/ */
import { describe, it, expect, beforeAll, afterAll } from 'vitest'; import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { FixtureServer, getAllStepFixtureMappings, PlaywrightAutomationAdapter } from 'core/automation/infrastructure/adapters/automation'; import { FixtureServer, getAllStepFixtureMappings, PlaywrightAutomationAdapter } from 'core/automation/infrastructure//automation';
declare const getComputedStyle: any; declare const getComputedStyle: any;
declare const document: any; declare const document: any;

View File

@@ -1,5 +1,5 @@
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { MockBrowserAutomationAdapter } from 'core/automation/infrastructure/adapters/automation'; import { MockBrowserAutomationAdapter } from 'core/automation/infrastructure//automation';
import { StepId } from '@gridpilot/automation/domain/value-objects/StepId'; import { StepId } from '@gridpilot/automation/domain/value-objects/StepId';
describe('MockBrowserAutomationAdapter Integration Tests', () => { describe('MockBrowserAutomationAdapter Integration Tests', () => {

View File

@@ -1,6 +1,6 @@
import { describe, test, expect } from 'vitest' import { describe, test, expect } from 'vitest'
import type { Page } from 'playwright' import type { Page } from 'playwright'
import { PlaywrightAutomationAdapter } from 'core/automation/infrastructure/adapters/automation' import { PlaywrightAutomationAdapter } from 'core/automation/infrastructure//automation'
describe('CarsFlow integration', () => { describe('CarsFlow integration', () => {
test('adapter emits panel-attached then action-started then action-complete for performAddCar', async () => { test('adapter emits panel-attached then action-started then action-complete for performAddCar', async () => {

View File

@@ -4,7 +4,7 @@ import type { AutomationEvent } from 'core/automation/application/ports/IAutomat
import type { import type {
IAutomationLifecycleEmitter, IAutomationLifecycleEmitter,
LifecycleCallback, LifecycleCallback,
} from 'core/automation/infrastructure/adapters/IAutomationLifecycleEmitter'; } from 'core/automation/infrastructure//IAutomationLifecycleEmitter';
import type { import type {
OverlayAction, OverlayAction,
ActionAck, ActionAck,

View File

@@ -2,7 +2,7 @@ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { DIContainer } from '../../../..//apps/companion/main/di-container'; import { DIContainer } from '../../../..//apps/companion/main/di-container';
import type { HostedSessionConfig } from '@gridpilot/automation/domain/types/HostedSessionConfig'; import type { HostedSessionConfig } from '@gridpilot/automation/domain/types/HostedSessionConfig';
import { StepId } from '@gridpilot/automation/domain/value-objects/StepId'; import { StepId } from '@gridpilot/automation/domain/value-objects/StepId';
import { PlaywrightAutomationAdapter } from '../../../..//core/automation/infrastructure/adapters/automation'; import { PlaywrightAutomationAdapter } from '../../../..//core/automation/infrastructure//automation';
describe('companion start automation - browser mode refresh wiring', () => { describe('companion start automation - browser mode refresh wiring', () => {
const originalEnv = { ...process.env }; const originalEnv = { ...process.env };

View File

@@ -2,7 +2,7 @@ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { DIContainer } from '../../../..//apps/companion/main/di-container'; import { DIContainer } from '../../../..//apps/companion/main/di-container';
import type { HostedSessionConfig } from '@gridpilot/automation/domain/types/HostedSessionConfig'; import type { HostedSessionConfig } from '@gridpilot/automation/domain/types/HostedSessionConfig';
import { StepId } from '@gridpilot/automation/domain/value-objects/StepId'; import { StepId } from '@gridpilot/automation/domain/value-objects/StepId';
import { PlaywrightAutomationAdapter } from '../../../..//core/automation/infrastructure/adapters/automation'; import { PlaywrightAutomationAdapter } from '../../../..//core/automation/infrastructure//automation';
describe('companion start automation - browser not connected at step 1', () => { describe('companion start automation - browser not connected at step 1', () => {
const originalEnv = { ...process.env }; const originalEnv = { ...process.env };

View File

@@ -1,7 +1,7 @@
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { DIContainer } from '../../../..//apps/companion/main/di-container'; import { DIContainer } from '../../../..//apps/companion/main/di-container';
import type { HostedSessionConfig } from '@gridpilot/automation/domain/types/HostedSessionConfig'; import type { HostedSessionConfig } from '@gridpilot/automation/domain/types/HostedSessionConfig';
import { PlaywrightAutomationAdapter } from '../../../..//core/automation/infrastructure/adapters/automation'; import { PlaywrightAutomationAdapter } from '../../../..//core/automation/infrastructure//automation';
describe('companion start automation - browser connection failure before steps', () => { describe('companion start automation - browser connection failure before steps', () => {
const originalEnv = { ...process.env }; const originalEnv = { ...process.env };

View File

@@ -5,9 +5,9 @@ import { CheckAuthenticationUseCase } from '../../core/automation/application/us
import { InitiateLoginUseCase } from '../../core/automation/application/use-cases/InitiateLoginUseCase'; import { InitiateLoginUseCase } from '../../core/automation/application/use-cases/InitiateLoginUseCase';
import { ClearSessionUseCase } from '../../core/automation/application/use-cases/ClearSessionUseCase'; import { ClearSessionUseCase } from '../../core/automation/application/use-cases/ClearSessionUseCase';
import { ConfirmCheckoutUseCase } from '../../core/automation/application/use-cases/ConfirmCheckoutUseCase'; import { ConfirmCheckoutUseCase } from '../../core/automation/application/use-cases/ConfirmCheckoutUseCase';
import { PlaywrightAutomationAdapter } from 'core/automation/infrastructure/adapters/automation'; import { PlaywrightAutomationAdapter } from 'core/automation/infrastructure//automation';
import { InMemorySessionRepository } from '../../core/automation/infrastructure/repositories/InMemorySessionRepository'; import { InMemorySessionRepository } from '../../core/automation/infrastructure/repositories/InMemorySessionRepository';
import { NoOpLogAdapter } from '../../core/automation/infrastructure/adapters/logging/NoOpLogAdapter'; import { NoOpLogAdapter } from '../../core/automation/infrastructure//logging/NoOpLogAdapter';
// Mock Electron's app module // Mock Electron's app module
vi.mock('electron', () => ({ vi.mock('electron', () => ({

View File

@@ -1,6 +1,6 @@
import { describe, it, expect, afterEach, beforeAll, afterAll } from 'vitest'; import { describe, it, expect, afterEach, beforeAll, afterAll } from 'vitest';
import { PlaywrightAutomationAdapter, FixtureServer } from 'core/automation/infrastructure/adapters/automation'; import { PlaywrightAutomationAdapter, FixtureServer } from 'core/automation/infrastructure//automation';
import { NoOpLogAdapter } from '../../core/automation/infrastructure/adapters/logging/NoOpLogAdapter'; import { NoOpLogAdapter } from '../../core/automation/infrastructure//logging/NoOpLogAdapter';
describe('Playwright Adapter Smoke Tests', () => { describe('Playwright Adapter Smoke Tests', () => {
let adapter: PlaywrightAutomationAdapter | undefined; let adapter: PlaywrightAutomationAdapter | undefined;