Compare commits

..

13 Commits

11 changed files with 45 additions and 63 deletions

View File

@@ -1,12 +0,0 @@
.git
.github
.node_modules
dist
coverage
*.log
.env*
test
*.spec.ts
*.e2e-spec.ts
README.md
AGENTS.md

View File

@@ -8,11 +8,9 @@ RUN pnpm build
FROM node:20-alpine
WORKDIR /app
RUN npm i -g pnpm
COPY --from=builder /app/package.json ./package.json
COPY --from=builder /app/pnpm-lock.yaml ./pnpm-lock.yaml
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/prisma ./prisma
COPY --from=builder /app/prisma.config.ts ./prisma.config.ts
COPY --from=builder /app/dist ./dist
RUN pnpm install --prod --frozen-lockfile
COPY --from=builder /app/package.json ./package.json
CMD ["node", "dist/src/main.js"]

View File

@@ -47,9 +47,9 @@
"dotenv": "^17.2.3",
"ioredis": "^5.8.2",
"jsonwebtoken": "^9.0.2",
"helmet": "^8.1.0",
"passport": "^0.7.0",
"passport-discord": "^0.1.4",
"helmet": "^8.1.0",
"passport-google-oauth20": "^2.0.0",
"passport-jwt": "^4.0.1",
"pg": "^8.16.3",

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

@@ -41,7 +41,7 @@ function validateEnvironment(
}
// Validate PORT if provided
if (config.PORT && isNaN(Number(config.PORT))) {
if (config.PORT !== undefined && !Number.isFinite(Number(config.PORT))) {
throw new Error('PORT must be a valid number');
}

View File

@@ -108,10 +108,6 @@ class RedisLifecycleService implements OnModuleDestroy {
},
});
client.on('error', (err) => {
logger.error('Redis connection error', err);
});
client.on('connect', () => {
logger.log(`Connected to Redis at ${host}:${port}`);
});

View File

@@ -9,9 +9,9 @@ export type AuthenticatedSocket = BaseSocket<
{
user?: AuthenticatedUser;
userId?: string;
senderName?: string;
senderNameCachedAt?: number;
activeDollId?: string | null;
friends?: Set<string>; // Set of friend user IDs
senderName?: string;
senderNameCachedAt?: number;
}
>;

View File

@@ -41,7 +41,6 @@ export class ConnectionHandler {
// Initialize defaults
client.data.activeDollId = null;
client.data.friends = new Set();
client.data.senderName = undefined;
// userId is not set yet, it will be set in handleClientInitialize
this.logger.log(`WebSocket authenticated (Pending Init): ${payload.sub}`);

View File

@@ -1,9 +1,9 @@
import { Logger } from '@nestjs/common';
import { WsException } from '@nestjs/websockets';
import type { AuthenticatedSocket } from '../../../types/socket';
import { PrismaService } from '../../../database/prisma.service';
import { SendInteractionDto } from '../../dto/send-interaction.dto';
import { InteractionPayloadDto } from '../../dto/interaction-payload.dto';
import { PrismaService } from '../../../database/prisma.service';
import { UserSocketService } from '../user-socket.service';
import { WsNotificationService } from '../ws-notification.service';
import { WS_EVENT } from '../ws-events';

View File

@@ -22,6 +22,8 @@ type MockSocket = {
userId?: string;
activeDollId?: string | null;
friends?: Set<string>;
senderName?: string;
senderNameCachedAt?: number;
};
handshake?: any;
disconnect?: jest.Mock;

View File

@@ -132,12 +132,6 @@ export class StateGateway
}
}
onModuleDestroy() {
if (this.redisSubscriber) {
this.redisSubscriber.removeAllListeners('message');
}
}
async isUserOnline(userId: string): Promise<boolean> {
return this.userSocketService.isUserOnline(userId);
}
@@ -165,4 +159,10 @@ export class StateGateway
) {
await this.interactionHandler.handleSendInteraction(client, data);
}
onModuleDestroy() {
if (this.redisSubscriber) {
this.redisSubscriber.removeAllListeners('message');
}
}
}