Compare commits

...

4 Commits

5 changed files with 58 additions and 51 deletions

9
pnpm-lock.yaml generated
View File

@@ -62,6 +62,9 @@ importers:
dotenv:
specifier: ^17.2.3
version: 17.2.3
helmet:
specifier: ^8.1.0
version: 8.1.0
ioredis:
specifier: ^5.8.2
version: 5.8.2
@@ -2298,6 +2301,10 @@ packages:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
helmet@8.1.0:
resolution: {integrity: sha512-jOiHyAZsmnr8LqoPGmCjYAaiuWwjAPLgY8ZX2XrmHawt99/u1y6RgrZMTeoPfpUbV96HOalYgz1qzkRbw54Pmg==}
engines: {node: '>=18.0.0'}
hono@4.7.10:
resolution: {integrity: sha512-QkACju9MiN59CKSY5JsGZCYmPZkA6sIW6OFCUp7qDjZu6S6KHtJHhAc9Uy9mV9F8PJ1/HQ3ybZF2yjCa/73fvQ==}
engines: {node: '>=16.9.0'}
@@ -6227,6 +6234,8 @@ snapshots:
dependencies:
function-bind: 1.1.2
helmet@8.1.0: {}
hono@4.7.10: {}
html-escaper@2.0.2: {}

View File

@@ -3,7 +3,6 @@
generator client {
provider = "prisma-client-js"
output = "../node_modules/.prisma/client"
}
datasource db {
@@ -50,10 +49,10 @@ model User {
activeDollId String? @map("active_doll_id")
activeDoll Doll? @relation("ActiveDoll", fields: [activeDollId], references: [id])
sentFriendRequests FriendRequest[] @relation("SentFriendRequests")
receivedFriendRequests FriendRequest[] @relation("ReceivedFriendRequests")
userFriendships Friendship[] @relation("UserFriendships")
friendFriendships Friendship[] @relation("FriendFriendships")
sentFriendRequests FriendRequest[] @relation("SentFriendRequests")
receivedFriendRequests FriendRequest[] @relation("ReceivedFriendRequests")
userFriendships Friendship[] @relation("UserFriendships")
friendFriendships Friendship[] @relation("FriendFriendships")
dolls Doll[]
authIdentities AuthIdentity[]
authSessions AuthSession[]
@@ -63,17 +62,17 @@ model User {
}
model AuthIdentity {
id String @id @default(uuid())
provider AuthProvider
providerSubject String @map("provider_subject")
providerEmail String? @map("provider_email")
providerName String? @map("provider_name")
providerUsername String? @map("provider_username")
providerPicture String? @map("provider_picture")
emailVerified Boolean @default(false) @map("email_verified")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
userId String @map("user_id")
id String @id @default(uuid())
provider AuthProvider
providerSubject String @map("provider_subject")
providerEmail String? @map("provider_email")
providerName String? @map("provider_name")
providerUsername String? @map("provider_username")
providerPicture String? @map("provider_picture")
emailVerified Boolean @default(false) @map("email_verified")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
userId String @map("user_id")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@ -83,14 +82,14 @@ model AuthIdentity {
}
model AuthSession {
id String @id @default(uuid())
id String @id @default(uuid())
provider AuthProvider?
refreshTokenHash String @unique @map("refresh_token_hash")
expiresAt DateTime @map("expires_at")
revokedAt DateTime? @map("revoked_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
userId String @map("user_id")
refreshTokenHash String @unique @map("refresh_token_hash")
expiresAt DateTime @map("expires_at")
revokedAt DateTime? @map("revoked_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
userId String @map("user_id")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@ -99,13 +98,13 @@ model AuthSession {
}
model AuthExchangeCode {
id String @id @default(uuid())
provider AuthProvider
codeHash String @unique @map("code_hash")
expiresAt DateTime @map("expires_at")
consumedAt DateTime? @map("consumed_at")
createdAt DateTime @default(now()) @map("created_at")
userId String @map("user_id")
id String @id @default(uuid())
provider AuthProvider
codeHash String @unique @map("code_hash")
expiresAt DateTime @map("expires_at")
consumedAt DateTime? @map("consumed_at")
createdAt DateTime @default(now()) @map("created_at")
userId String @map("user_id")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)

View File

@@ -22,6 +22,7 @@ describe('UsersController', () => {
const mockAuthUser: AuthenticatedUser = {
userId: 'uuid-123',
email: 'test@example.com',
tokenType: 'access',
roles: ['user'],
};

View File

@@ -3,7 +3,6 @@ import { Test, TestingModule } from '@nestjs/testing';
import { StateGateway } from './state.gateway';
import { AuthenticatedSocket } from '../../types/socket';
import { JwtVerificationService } from '../../auth/services/jwt-verification.service';
import { UsersService } from '../../users/users.service';
import { PrismaService } from '../../database/prisma.service';
import { UserSocketService } from './user-socket.service';
import { WsNotificationService } from './ws-notification.service';
@@ -23,6 +22,8 @@ type MockSocket = {
userId?: string;
activeDollId?: string | null;
friends?: Set<string>;
senderName?: string;
senderNameCachedAt?: number;
};
handshake?: any;
disconnect?: jest.Mock;
@@ -39,7 +40,6 @@ describe('StateGateway', () => {
sockets: { sockets: { size: number; get: jest.Mock } };
to: jest.Mock;
};
let mockUsersService: Partial<UsersService>;
let mockJwtVerificationService: Partial<JwtVerificationService>;
let mockPrismaService: Partial<PrismaService>;
let mockUserSocketService: Partial<UserSocketService>;
@@ -67,12 +67,6 @@ describe('StateGateway', () => {
}),
};
mockUsersService = {
findOne: jest.fn().mockResolvedValue({
id: 'user-id',
}),
};
mockJwtVerificationService = {
extractToken: jest.fn((handshake) => handshake.auth?.token),
verifyToken: jest.fn().mockReturnValue({
@@ -83,7 +77,12 @@ describe('StateGateway', () => {
mockPrismaService = {
user: {
findUnique: jest.fn().mockResolvedValue({ activeDollId: 'doll-123' }),
findUnique: jest.fn().mockResolvedValue({
id: 'user-id',
name: 'Test User',
username: 'test-user',
activeDollId: 'doll-123',
}),
} as any,
friendship: {
findMany: jest.fn().mockResolvedValue([]),
@@ -119,7 +118,6 @@ describe('StateGateway', () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
StateGateway,
{ provide: UsersService, useValue: mockUsersService },
{
provide: JwtVerificationService,
useValue: mockJwtVerificationService,
@@ -190,7 +188,6 @@ describe('StateGateway', () => {
);
// Should NOT call these anymore in handleConnection
expect(mockUsersService.findOne).not.toHaveBeenCalled();
expect(mockUserSocketService.setSocket).not.toHaveBeenCalled();
// Should set data on client
@@ -244,6 +241,9 @@ describe('StateGateway', () => {
// Mock Prisma responses
(mockPrismaService.user!.findUnique as jest.Mock).mockResolvedValue({
id: 'user-id',
name: 'Test User',
username: 'test-user',
activeDollId: 'doll-123',
});
(mockPrismaService.friendship!.findMany as jest.Mock).mockResolvedValue([
@@ -255,32 +255,29 @@ describe('StateGateway', () => {
mockClient as unknown as AuthenticatedSocket,
);
// 1. Load User
expect(mockUsersService.findOne).toHaveBeenCalledWith('test-sub');
// 2. Set Socket
// 1. Set Socket
expect(mockUserSocketService.setSocket).toHaveBeenCalledWith(
'user-id',
'client1',
);
// 3. Fetch State (DB)
// 2. Fetch State (DB)
expect(mockPrismaService.user!.findUnique).toHaveBeenCalledWith({
where: { id: 'user-id' },
select: { activeDollId: true },
where: { id: 'test-sub' },
select: { id: true, name: true, username: true, activeDollId: true },
});
expect(mockPrismaService.friendship!.findMany).toHaveBeenCalledWith({
where: { userId: 'user-id' },
where: { userId: 'test-sub' },
select: { friendId: true },
});
// 4. Update Client Data
// 3. Update Client Data
expect(mockClient.data.userId).toBe('user-id');
expect(mockClient.data.activeDollId).toBe('doll-123');
expect(mockClient.data.friends).toContain('friend-1');
expect(mockClient.data.friends).toContain('friend-2');
// 5. Emit Initialized
// 4. Emit Initialized
expect(mockClient.emit).toHaveBeenCalledWith('initialized', {
userId: 'user-id',
activeDollId: 'doll-123',

View File

@@ -152,6 +152,7 @@ export class StateGateway
await this.statusHandler.handleClientReportUserStatus(client, data);
}
@SubscribeMessage(WS_EVENT.CLIENT_SEND_INTERACTION)
async handleSendInteraction(
client: AuthenticatedSocket,
data: SendInteractionDto,