fix issues in core

This commit is contained in:
2025-12-23 17:31:45 +01:00
parent d04a21fe02
commit 4318b380d9
34 changed files with 116 additions and 103 deletions

View File

@@ -7,6 +7,7 @@
"sourceType": "module", "sourceType": "module",
"ecmaVersion": 2022 "ecmaVersion": 2022
}, },
"ignorePatterns": ["**/dist/**", "**/*.d.ts"],
"settings": { "settings": {
"import/resolver": { "import/resolver": {
"typescript": {} "typescript": {}
@@ -83,6 +84,54 @@
] ]
} }
}, },
{
"files": ["core/**/application/dto/**/*.ts", "core/**/application/dtos/**/*.ts"],
"rules": {
"no-restricted-syntax": [
"error",
{
"selector": "Program",
"message": "core/*/application/dto is forbidden. Use application result models + output ports; DTOs belong in API/website layers."
}
]
}
},
{
"files": ["core/**/infrastructure/**/*.ts"],
"rules": {
"no-restricted-syntax": [
"error",
{
"selector": "Program",
"message": "core/*/infrastructure is forbidden. Implementations must live in adapters/ and be wired in apps/."
}
]
}
},
{
"files": ["core/**/domain/ports/**/*.ts"],
"rules": {
"no-restricted-syntax": [
"error",
{
"selector": "Program",
"message": "core/*/domain/ports is forbidden. Ports belong in application/ports (or shared application layer), not domain."
}
]
}
},
{
"files": ["core/**/shared/presentation/**/*.ts"],
"rules": {
"no-restricted-syntax": [
"error",
{
"selector": "Program",
"message": "core/shared/presentation is forbidden. Presentation belongs in API or website layers."
}
]
}
},
{ {
"files": ["apps/website/**/*.ts"], "files": ["apps/website/**/*.ts"],
"rules": { "rules": {

View File

@@ -4,13 +4,12 @@
* Manages user session using cookies. This is a placeholder implementation. * Manages user session using cookies. This is a placeholder implementation.
*/ */
import type { AuthenticatedUserDTO } from '@core/identity/application/dto/AuthenticatedUserDTO'; import type { AuthenticatedUser } from '@core/identity/application/ports/IdentityProviderPort';
import type { AuthSessionDTO } from '@core/identity/application/dto/AuthSessionDTO'; import type { AuthSession, IdentitySessionPort } from '@core/identity/application/ports/IdentitySessionPort';
import type { IdentitySessionPort } from '@core/identity/application/ports/IdentitySessionPort'; import type { Logger } from '@core/shared/application';
import { Logger } from '@core/shared/application';
export class CookieIdentitySessionAdapter implements IdentitySessionPort { export class CookieIdentitySessionAdapter implements IdentitySessionPort {
private currentSession: AuthSessionDTO | null = null; private currentSession: AuthSession | null = null;
constructor(private readonly logger: Logger) { constructor(private readonly logger: Logger) {
this.logger.info('CookieIdentitySessionAdapter initialized.'); this.logger.info('CookieIdentitySessionAdapter initialized.');
@@ -18,14 +17,14 @@ export class CookieIdentitySessionAdapter implements IdentitySessionPort {
// For demo, we'll start with no session. // For demo, we'll start with no session.
} }
async getCurrentSession(): Promise<AuthSessionDTO | null> { async getCurrentSession(): Promise<AuthSession | null> {
this.logger.debug('[CookieIdentitySessionAdapter] Getting current session.'); this.logger.debug('[CookieIdentitySessionAdapter] Getting current session.');
return Promise.resolve(this.currentSession); return Promise.resolve(this.currentSession);
} }
async createSession(user: AuthenticatedUserDTO): Promise<AuthSessionDTO> { async createSession(user: AuthenticatedUser): Promise<AuthSession> {
this.logger.debug(`[CookieIdentitySessionAdapter] Creating session for user: ${user.id}`); this.logger.debug(`[CookieIdentitySessionAdapter] Creating session for user: ${user.id}`);
const newSession: AuthSessionDTO = { const newSession: AuthSession = {
user: user, user: user,
issuedAt: Date.now(), issuedAt: Date.now(),
expiresAt: Date.now() + 3600 * 1000, // 1 hour expiration expiresAt: Date.now() + 3600 * 1000, // 1 hour expiration

View File

@@ -33,7 +33,7 @@ import { InMemoryDriverRatingProvider } from '@adapters/racing/ports/InMemoryDri
import { InMemoryDriverStatsService } from '@adapters/racing/services/InMemoryDriverStatsService'; import { InMemoryDriverStatsService } from '@adapters/racing/services/InMemoryDriverStatsService';
import { InMemoryRankingService } from '@adapters/racing/services/InMemoryRankingService'; import { InMemoryRankingService } from '@adapters/racing/services/InMemoryRankingService';
import { IImageServicePort } from '@core/racing/application/ports/IImageServicePort'; import { IImageServicePort } from '@core/racing/application/ports/IImageServicePort';
import { InMemorySocialGraphRepository } from '@core/social/infrastructure/inmemory/InMemorySocialAndFeed'; import { InMemorySocialGraphRepository } from '@adapters/social/persistence/inmemory/InMemorySocialAndFeed';
// Import presenters // Import presenters
import { CompleteOnboardingPresenter } from './presenters/CompleteOnboardingPresenter'; import { CompleteOnboardingPresenter } from './presenters/CompleteOnboardingPresenter';

View File

@@ -1,4 +1,4 @@
import { Presenter } from '@core/shared/presentation'; import type { Presenter } from '../../../shared/presentation/Presenter';
import type { GetLeagueProtestsResult } from '@core/racing/application/use-cases/GetLeagueProtestsUseCase'; import type { GetLeagueProtestsResult } from '@core/racing/application/use-cases/GetLeagueProtestsUseCase';
import { LeagueAdminProtestsDTO } from '../dtos/LeagueAdminProtestsDTO'; import { LeagueAdminProtestsDTO } from '../dtos/LeagueAdminProtestsDTO';
import { ProtestDTO } from '../dtos/ProtestDTO'; import { ProtestDTO } from '../dtos/ProtestDTO';

View File

@@ -1,4 +1,4 @@
import { Presenter } from '@core/shared/presentation'; import type { Presenter } from '../../../shared/presentation/Presenter';
import type { GetLeagueSeasonsResult } from '@core/racing/application/use-cases/GetLeagueSeasonsUseCase'; import type { GetLeagueSeasonsResult } from '@core/racing/application/use-cases/GetLeagueSeasonsUseCase';
import { LeagueSeasonSummaryDTO } from '../dtos/LeagueSeasonSummaryDTO'; import { LeagueSeasonSummaryDTO } from '../dtos/LeagueSeasonSummaryDTO';

View File

@@ -1,6 +1,6 @@
import type { GetLeagueStandingsResult } from '@core/racing/application/use-cases/GetLeagueStandingsUseCase'; import type { GetLeagueStandingsResult } from '@core/racing/application/use-cases/GetLeagueStandingsUseCase';
import { LeagueStandingsDTO } from '../dtos/LeagueStandingsDTO'; import { LeagueStandingsDTO } from '../dtos/LeagueStandingsDTO';
import type { Presenter } from '@core/shared/presentation'; import type { Presenter } from '../../../shared/presentation/Presenter';
export class LeagueStandingsPresenter implements Presenter<GetLeagueStandingsResult, LeagueStandingsDTO> { export class LeagueStandingsPresenter implements Presenter<GetLeagueStandingsResult, LeagueStandingsDTO> {
private result: LeagueStandingsDTO | null = null; private result: LeagueStandingsDTO | null = null;

View File

@@ -1,6 +1,6 @@
import type { GetLeagueStatsResult } from '@core/racing/application/use-cases/GetLeagueStatsUseCase'; import type { GetLeagueStatsResult } from '@core/racing/application/use-cases/GetLeagueStatsUseCase';
import { LeagueStatsDTO } from '../dtos/LeagueStatsDTO'; import { LeagueStatsDTO } from '../dtos/LeagueStatsDTO';
import type { Presenter } from '@core/shared/presentation'; import type { Presenter } from '../../../shared/presentation/Presenter';
export class LeagueStatsPresenter implements Presenter<GetLeagueStatsResult, LeagueStatsDTO> { export class LeagueStatsPresenter implements Presenter<GetLeagueStatsResult, LeagueStatsDTO> {
private result: LeagueStatsDTO | null = null; private result: LeagueStatsDTO | null = null;

View File

@@ -1,4 +1,4 @@
import type { Presenter } from '@core/shared/presentation/Presenter'; import type { Presenter } from '../../../shared/presentation/Presenter';
import { AwardPrizeResultDTO } from '../dtos/AwardPrizeDTO'; import { AwardPrizeResultDTO } from '../dtos/AwardPrizeDTO';
export interface IAwardPrizePresenter extends Presenter<AwardPrizeResultDTO, AwardPrizeResultDTO> {} export interface IAwardPrizePresenter extends Presenter<AwardPrizeResultDTO, AwardPrizeResultDTO> {}

View File

@@ -1,4 +1,4 @@
import type { Presenter } from '@core/shared/presentation/Presenter'; import type { Presenter } from '../../../shared/presentation/Presenter';
import { CreatePrizeResultDTO } from '../dtos/CreatePrizeDTO'; import { CreatePrizeResultDTO } from '../dtos/CreatePrizeDTO';
export interface ICreatePrizePresenter extends Presenter<CreatePrizeResultDTO, CreatePrizeResultDTO> {} export interface ICreatePrizePresenter extends Presenter<CreatePrizeResultDTO, CreatePrizeResultDTO> {}

View File

@@ -1,4 +1,4 @@
import type { Presenter } from '@core/shared/presentation/Presenter'; import type { Presenter } from '../../../shared/presentation/Presenter';
import { DeletePrizeResultDTO } from '../dtos/DeletePrizeDTO'; import { DeletePrizeResultDTO } from '../dtos/DeletePrizeDTO';
export interface IDeletePrizePresenter extends Presenter<DeletePrizeResultDTO, DeletePrizeResultDTO> {} export interface IDeletePrizePresenter extends Presenter<DeletePrizeResultDTO, DeletePrizeResultDTO> {}

View File

@@ -1,4 +1,4 @@
import type { Presenter } from '@core/shared/presentation/Presenter'; import type { Presenter } from '../../../shared/presentation/Presenter';
import { GetMembershipFeesResultDTO } from '../dtos/GetMembershipFeesDTO'; import { GetMembershipFeesResultDTO } from '../dtos/GetMembershipFeesDTO';
export interface IGetMembershipFeesPresenter extends Presenter<GetMembershipFeesResultDTO, GetMembershipFeesResultDTO> {} export interface IGetMembershipFeesPresenter extends Presenter<GetMembershipFeesResultDTO, GetMembershipFeesResultDTO> {}

View File

@@ -1,4 +1,4 @@
import type { Presenter } from '@core/shared/presentation/Presenter'; import type { Presenter } from '../../../shared/presentation/Presenter';
import { GetPrizesResultDTO } from '../dtos/GetPrizesDTO'; import { GetPrizesResultDTO } from '../dtos/GetPrizesDTO';
export interface IGetPrizesPresenter extends Presenter<GetPrizesResultDTO, GetPrizesResultDTO> {} export interface IGetPrizesPresenter extends Presenter<GetPrizesResultDTO, GetPrizesResultDTO> {}

View File

@@ -1,4 +1,4 @@
import type { Presenter } from '@core/shared/presentation/Presenter'; import type { Presenter } from '../../../shared/presentation/Presenter';
import { GetWalletResultDTO } from '../dtos/GetWalletDTO'; import { GetWalletResultDTO } from '../dtos/GetWalletDTO';
export interface IGetWalletPresenter extends Presenter<GetWalletResultDTO, GetWalletResultDTO> {} export interface IGetWalletPresenter extends Presenter<GetWalletResultDTO, GetWalletResultDTO> {}

View File

@@ -1,4 +1,4 @@
import type { Presenter } from '@core/shared/presentation/Presenter'; import type { Presenter } from '../../../shared/presentation/Presenter';
import { ProcessWalletTransactionResultDTO } from '../dtos/ProcessWalletTransactionDTO'; import { ProcessWalletTransactionResultDTO } from '../dtos/ProcessWalletTransactionDTO';
export interface IProcessWalletTransactionPresenter extends Presenter<ProcessWalletTransactionResultDTO, ProcessWalletTransactionResultDTO> {} export interface IProcessWalletTransactionPresenter extends Presenter<ProcessWalletTransactionResultDTO, ProcessWalletTransactionResultDTO> {}

View File

@@ -1,4 +1,4 @@
import type { Presenter } from '@core/shared/presentation/Presenter'; import type { Presenter } from '../../../shared/presentation/Presenter';
import { UpdateMemberPaymentResultDTO } from '../dtos/UpdateMemberPaymentDTO'; import { UpdateMemberPaymentResultDTO } from '../dtos/UpdateMemberPaymentDTO';
export interface IUpdateMemberPaymentPresenter extends Presenter<UpdateMemberPaymentResultDTO, UpdateMemberPaymentResultDTO> {} export interface IUpdateMemberPaymentPresenter extends Presenter<UpdateMemberPaymentResultDTO, UpdateMemberPaymentResultDTO> {}

View File

@@ -1,4 +1,4 @@
import type { Presenter } from '@core/shared/presentation/Presenter'; import type { Presenter } from '../../../shared/presentation/Presenter';
import { UpsertMembershipFeeResultDTO } from '../dtos/UpsertMembershipFeeDTO'; import { UpsertMembershipFeeResultDTO } from '../dtos/UpsertMembershipFeeDTO';
export interface IUpsertMembershipFeePresenter extends Presenter<UpsertMembershipFeeResultDTO, UpsertMembershipFeeResultDTO> {} export interface IUpsertMembershipFeePresenter extends Presenter<UpsertMembershipFeeResultDTO, UpsertMembershipFeeResultDTO> {}

View File

@@ -0,0 +1,5 @@
export interface Presenter<Input, ResponseModel> {
present(input: Input): void;
getResponseModel(): ResponseModel | null;
reset(): void;
}

View File

@@ -1,6 +0,0 @@
export interface Logger {
debug(message: string, ...args: unknown[]): void;
info(message: string, ...args: unknown[]): void;
warn(message: string, ...args: unknown[]): void;
error(message: string, ...args: unknown[]): void;
}

View File

@@ -1,7 +1,6 @@
import { describe, it, expect, vi, type Mock } from 'vitest'; import { describe, it, expect, vi, type Mock } from 'vitest';
import { GetCurrentUserSessionUseCase } from './GetCurrentUserSessionUseCase'; import { GetCurrentUserSessionUseCase } from './GetCurrentUserSessionUseCase';
import type { IdentitySessionPort } from '../ports/IdentitySessionPort'; import type { AuthSession, IdentitySessionPort } from '../ports/IdentitySessionPort';
import type { AuthSessionDTO } from '../dto/AuthSessionDTO';
import type { Logger, UseCaseOutputPort } from '@core/shared/application'; import type { Logger, UseCaseOutputPort } from '@core/shared/application';
describe('GetCurrentUserSessionUseCase', () => { describe('GetCurrentUserSessionUseCase', () => {
@@ -11,7 +10,7 @@ describe('GetCurrentUserSessionUseCase', () => {
clearSession: Mock; clearSession: Mock;
}; };
let logger: Logger; let logger: Logger;
let output: UseCaseOutputPort<AuthSessionDTO | null> & { present: Mock }; let output: UseCaseOutputPort<AuthSession | null> & { present: Mock };
let useCase: GetCurrentUserSessionUseCase; let useCase: GetCurrentUserSessionUseCase;
beforeEach(() => { beforeEach(() => {
@@ -40,7 +39,7 @@ describe('GetCurrentUserSessionUseCase', () => {
}); });
it('returns the current auth session when one exists', async () => { it('returns the current auth session when one exists', async () => {
const session: AuthSessionDTO = { const session: AuthSession = {
user: { user: {
id: 'user-1', id: 'user-1',
email: 'test@example.com', email: 'test@example.com',

View File

@@ -2,9 +2,8 @@ import { describe, it, expect, vi, type Mock } from 'vitest';
import { HandleAuthCallbackUseCase } from './HandleAuthCallbackUseCase'; import { HandleAuthCallbackUseCase } from './HandleAuthCallbackUseCase';
import type { IdentityProviderPort } from '../ports/IdentityProviderPort'; import type { IdentityProviderPort } from '../ports/IdentityProviderPort';
import type { IdentitySessionPort } from '../ports/IdentitySessionPort'; import type { IdentitySessionPort } from '../ports/IdentitySessionPort';
import type { AuthCallbackCommandDTO } from '../dto/AuthCallbackCommandDTO'; import type { AuthCallbackCommand, AuthenticatedUser } from '../ports/IdentityProviderPort';
import type { AuthenticatedUserDTO } from '../dto/AuthenticatedUserDTO'; import type { AuthSession } from '../ports/IdentitySessionPort';
import type { AuthSessionDTO } from '../dto/AuthSessionDTO';
import type { Logger, UseCaseOutputPort } from '@core/shared/application'; import type { Logger, UseCaseOutputPort } from '@core/shared/application';
describe('HandleAuthCallbackUseCase', () => { describe('HandleAuthCallbackUseCase', () => {
@@ -17,7 +16,7 @@ describe('HandleAuthCallbackUseCase', () => {
clearSession: Mock; clearSession: Mock;
}; };
let logger: Logger; let logger: Logger;
let output: UseCaseOutputPort<AuthSessionDTO> & { present: Mock }; let output: UseCaseOutputPort<AuthSession> & { present: Mock };
let useCase: HandleAuthCallbackUseCase; let useCase: HandleAuthCallbackUseCase;
beforeEach(() => { beforeEach(() => {
@@ -48,20 +47,20 @@ describe('HandleAuthCallbackUseCase', () => {
}); });
it('completes auth and creates a session', async () => { it('completes auth and creates a session', async () => {
const command: AuthCallbackCommandDTO = { const command: AuthCallbackCommand = {
provider: 'IRACING_DEMO', provider: 'IRACING_DEMO',
code: 'auth-code', code: 'auth-code',
state: 'state-123', state: 'state-123',
returnTo: 'https://app/callback', returnTo: 'https://app/callback',
}; };
const user: AuthenticatedUserDTO = { const user: AuthenticatedUser = {
id: 'user-1', id: 'user-1',
email: 'test@example.com', email: 'test@example.com',
displayName: 'Test User', displayName: 'Test User',
}; };
const session: AuthSessionDTO = { const session: AuthSession = {
user, user,
issuedAt: Date.now(), issuedAt: Date.now(),
expiresAt: Date.now() + 1000, expiresAt: Date.now() + 1000,

View File

@@ -2,8 +2,7 @@ import { describe, it, expect, vi, type Mock } from 'vitest';
import { SignupWithEmailUseCase } from './SignupWithEmailUseCase'; import { SignupWithEmailUseCase } from './SignupWithEmailUseCase';
import type { SignupWithEmailInput } from './SignupWithEmailUseCase'; import type { SignupWithEmailInput } from './SignupWithEmailUseCase';
import type { IUserRepository, StoredUser } from '../../domain/repositories/IUserRepository'; import type { IUserRepository, StoredUser } from '../../domain/repositories/IUserRepository';
import type { IdentitySessionPort } from '../ports/IdentitySessionPort'; import type { AuthSession, IdentitySessionPort } from '../ports/IdentitySessionPort';
import type { AuthSessionDTO } from '../dto/AuthSessionDTO';
import type { Logger, UseCaseOutputPort } from '@core/shared/application'; import type { Logger, UseCaseOutputPort } from '@core/shared/application';
type SignupWithEmailOutput = unknown; type SignupWithEmailOutput = unknown;
@@ -58,7 +57,7 @@ describe('SignupWithEmailUseCase', () => {
userRepository.findByEmail.mockResolvedValue(null); userRepository.findByEmail.mockResolvedValue(null);
const session: AuthSessionDTO = { const session: AuthSession = {
user: { user: {
id: 'user-1', id: 'user-1',
email: command.email.toLowerCase(), email: command.email.toLowerCase(),

View File

@@ -5,7 +5,7 @@
*/ */
import type { IUserRepository, StoredUser } from '../../domain/repositories/IUserRepository'; import type { IUserRepository, StoredUser } from '../../domain/repositories/IUserRepository';
import type { AuthenticatedUserDTO } from '../dto/AuthenticatedUserDTO'; import type { AuthenticatedUser } from '../ports/IdentityProviderPort';
import type { IdentitySessionPort } from '../ports/IdentitySessionPort'; import type { IdentitySessionPort } from '../ports/IdentitySessionPort';
import { Result } from '@core/shared/application/Result'; import { Result } from '@core/shared/application/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode'; import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
@@ -103,7 +103,7 @@ export class SignupWithEmailUseCase {
await this.userRepository.create(newUser); await this.userRepository.create(newUser);
// Create session // Create session
const authenticatedUser: AuthenticatedUserDTO = { const authenticatedUser: AuthenticatedUser = {
id: newUser.id, id: newUser.id,
displayName: newUser.displayName, displayName: newUser.displayName,
email: newUser.email, email: newUser.email,

View File

@@ -1,6 +0,0 @@
/**
* Infrastructure layer exports for notifications package
*/
// This infrastructure layer is empty as the actual implementations
// are in the adapters directory

View File

@@ -2,5 +2,4 @@ export * from './application/Result';
export * as application from './application'; export * as application from './application';
export * as domain from './domain'; export * as domain from './domain';
export * as errors from './errors'; export * as errors from './errors';
export * from './presentation';
export * from './application/AsyncUseCase'; export * from './application/AsyncUseCase';

View File

@@ -1,6 +0,0 @@
// This must not be used within core. It's in presentation layer, e.g. to be used in an API.
export interface Presenter<InputDTO, ResponseModel> {
present(input: InputDTO): void;
getResponseModel(): ResponseModel | null;
reset(): void;
}

View File

@@ -1 +0,0 @@
export * from './Presenter';

View File

@@ -1,22 +0,0 @@
export type FeedItemType =
| 'race_result'
| 'championship_standing'
| 'league_announcement'
| 'friend_joined_league'
| 'friend_won_race';
export interface FeedItemDTO {
id: string;
timestamp: string;
type: FeedItemType;
actorFriendId?: string;
actorDriverId?: string;
leagueId?: string;
raceId?: string;
teamId?: string;
position?: number;
headline: string;
body?: string;
ctaLabel?: string;
ctaHref?: string;
}

View File

@@ -1,8 +1,13 @@
export interface CurrentUserSocialDTO { export type SocialUserSummary = {
driverId: string; driverId: string;
displayName: string; displayName: string;
avatarUrl: string; avatarUrl: string;
countryCode: string; countryCode: string;
primaryTeamId?: string; primaryTeamId?: string;
primaryLeagueId?: string; primaryLeagueId?: string;
} };
export type SocialFriendSummary = SocialUserSummary & {
isOnline: boolean;
lastSeen: Date;
};

View File

@@ -2,8 +2,7 @@ import type { Logger, UseCaseOutputPort } from '@core/shared/application';
import { Result } from '@core/shared/application/Result'; import { Result } from '@core/shared/application/Result';
import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode'; import type { ApplicationErrorCode } from '@core/shared/errors/ApplicationErrorCode';
import type { ISocialGraphRepository } from '../../domain/repositories/ISocialGraphRepository'; import type { ISocialGraphRepository } from '../../domain/repositories/ISocialGraphRepository';
import type { CurrentUserSocialDTO } from '../dto/CurrentUserSocialDTO'; import type { SocialFriendSummary, SocialUserSummary } from '../types/SocialUser';
import type { FriendDTO } from '../dto/FriendDTO';
export interface GetCurrentUserSocialParams { export interface GetCurrentUserSocialParams {
driverId: string; driverId: string;
@@ -12,8 +11,8 @@ export interface GetCurrentUserSocialParams {
export type GetCurrentUserSocialInput = GetCurrentUserSocialParams; export type GetCurrentUserSocialInput = GetCurrentUserSocialParams;
export interface GetCurrentUserSocialResult { export interface GetCurrentUserSocialResult {
currentUser: CurrentUserSocialDTO; currentUser: SocialUserSummary;
friends: FriendDTO[]; friends: SocialFriendSummary[];
} }
export type GetCurrentUserSocialErrorCode = 'REPOSITORY_ERROR'; export type GetCurrentUserSocialErrorCode = 'REPOSITORY_ERROR';
@@ -61,15 +60,16 @@ export class GetCurrentUserSocialUseCase {
// The social graph context currently only knows about relationships. // The social graph context currently only knows about relationships.
// Profile fields for the current user are expected to be enriched by identity/profile contexts. // Profile fields for the current user are expected to be enriched by identity/profile contexts.
const friends: FriendDTO[] = friendsDomain.map((friend) => ({ const friends: SocialFriendSummary[] = friendsDomain.map((friend) => ({
driverId: friend.id, driverId: friend.id,
displayName: friend.name.toString(), displayName: friend.name.toString(),
avatarUrl: '', avatarUrl: '',
countryCode: '',
isOnline: false, isOnline: false,
lastSeen: new Date(), lastSeen: new Date(),
})); }));
const currentUser: CurrentUserSocialDTO = { const currentUser: SocialUserSummary = {
driverId, driverId,
displayName: '', displayName: '',
avatarUrl: '', avatarUrl: '',

View File

@@ -1,19 +1,19 @@
import { randomUUID } from 'crypto'; import { randomUUID } from 'crypto';
import { createStaticRacingSeed } from '@core/testing-support'; import type {
import type { IdentityProviderPort } from '../../application/ports/IdentityProviderPort'; AuthCallbackCommand,
import type { StartAuthCommandDTO } from '../../application/dto/StartAuthCommandDTO'; AuthenticatedUser,
import type { AuthCallbackCommandDTO } from '../../application/dto/AuthCallbackCommandDTO'; IdentityProviderPort,
import type { AuthenticatedUserDTO } from '../../application/dto/AuthenticatedUserDTO'; StartAuthCommand,
} from '@core/identity/application/ports/IdentityProviderPort';
export class IracingDemoIdentityProviderAdapter implements IdentityProviderPort { export class IracingDemoIdentityProviderAdapter implements IdentityProviderPort {
private readonly seedDriverId: string; private readonly seedDriverId: string;
constructor() { constructor() {
const seed = createStaticRacingSeed(42); this.seedDriverId = 'driver-1';
this.seedDriverId = seed.drivers[0]?.id ?? 'driver-1';
} }
async startAuth(command: StartAuthCommandDTO): Promise<{ redirectUrl: string; state: string }> { async startAuth(command: StartAuthCommand): Promise<{ redirectUrl: string; state: string }> {
const state = randomUUID(); const state = randomUUID();
const params = new URLSearchParams(); const params = new URLSearchParams();
@@ -29,7 +29,7 @@ export class IracingDemoIdentityProviderAdapter implements IdentityProviderPort
}; };
} }
async completeAuth(command: AuthCallbackCommandDTO): Promise<AuthenticatedUserDTO> { async completeAuth(command: AuthCallbackCommand): Promise<AuthenticatedUser> {
if (!command.code) { if (!command.code) {
throw new Error('Missing auth code'); throw new Error('Missing auth code');
} }
@@ -37,7 +37,7 @@ export class IracingDemoIdentityProviderAdapter implements IdentityProviderPort
throw new Error('Missing auth state'); throw new Error('Missing auth state');
} }
const user: AuthenticatedUserDTO = { const user: AuthenticatedUser = {
id: 'demo-user', id: 'demo-user',
displayName: 'GridPilot Demo Driver', displayName: 'GridPilot Demo Driver',
iracingCustomerId: '000000', iracingCustomerId: '000000',

View File

@@ -3,7 +3,7 @@ import { League } from '@core/racing/domain/entities/League';
import { Race } from '@core/racing/domain/entities/Race'; import { Race } from '@core/racing/domain/entities/Race';
import type { Result } from '@core/racing/domain/entities/Result'; import type { Result } from '@core/racing/domain/entities/Result';
import type { FeedItem } from '@core/social/domain/types/FeedItem'; import type { FeedItem } from '@core/social/domain/types/FeedItem';
import type { FriendDTO } from '@core/social/application/dto/FriendDTO'; import type { SocialFriendSummary } from '@core/social/application/types/SocialUser';
import { faker } from '../../helpers/faker/faker'; import { faker } from '../../helpers/faker/faker';
import { getLeagueBanner, getDriverAvatar } from '../../helpers/images/images'; import { getLeagueBanner, getDriverAvatar } from '../../helpers/images/images';
import type { Friendship, RacingMembership } from './RacingSeedCore'; import type { Friendship, RacingMembership } from './RacingSeedCore';
@@ -166,11 +166,11 @@ export function createFeedEvents(
export function buildFriends( export function buildFriends(
drivers: Driver[], drivers: Driver[],
memberships: RacingMembership[], memberships: RacingMembership[],
): FriendDTO[] { ): SocialFriendSummary[] {
return drivers.map((driver) => { return drivers.map((driver) => {
const membership = memberships.find((m) => m.driverId === driver.id); const membership = memberships.find((m) => m.driverId === driver.id);
const base: FriendDTO = { const base: SocialFriendSummary = {
driverId: driver.id, driverId: driver.id,
displayName: driver.name, displayName: driver.name,
avatarUrl: getDriverAvatar(driver.id), avatarUrl: getDriverAvatar(driver.id),

View File

@@ -5,7 +5,7 @@ import { Result } from '@core/racing/domain/entities/Result';
import { Standing } from '@core/racing/domain/entities/Standing'; import { Standing } from '@core/racing/domain/entities/Standing';
import type { FeedItem } from '@core/social/domain/types/FeedItem'; import type { FeedItem } from '@core/social/domain/types/FeedItem';
import type { FriendDTO } from '@core/social/application/dto/FriendDTO'; import type { SocialFriendSummary } from '@core/social/application/types/SocialUser';
import { faker } from '../../helpers/faker/faker'; import { faker } from '../../helpers/faker/faker';
import { getTeamLogo } from '../../helpers/images/images'; import { getTeamLogo } from '../../helpers/images/images';
@@ -128,7 +128,7 @@ export const sponsorshipPricings = staticSeed.sponsorshipPricings;
* Derived friend DTOs for UI consumption. * Derived friend DTOs for UI consumption.
* This preserves the previous demo-data `friends` shape. * This preserves the previous demo-data `friends` shape.
*/ */
export const friends: FriendDTO[] = buildFriends(staticSeed.drivers, staticSeed.memberships); export const friends: SocialFriendSummary[] = buildFriends(staticSeed.drivers, staticSeed.memberships);
/** /**
* Top leagues with banner URLs for UI. * Top leagues with banner URLs for UI.