refactor: validate user state with zod

This commit is contained in:
MythEclipse
2026-05-14 23:11:25 +07:00
parent 5010a4d1f1
commit 954faf6c5a
2 changed files with 48 additions and 29 deletions

View File

@@ -1,38 +1,22 @@
import { plainToClass } from "class-transformer"; import { z } from "zod";
import { IsBoolean, IsString, validate } from "class-validator";
export class UserStateUpdate { const userStateUpdateSchema = z.object({
@IsString() userId: z.string(),
userId!: string; username: z.string(),
avatar: z.string(),
speaking: z.boolean(),
});
@IsString() export type UserStateUpdate = z.infer<typeof userStateUpdateSchema>;
username!: string;
@IsString() export interface AudioMessage {
avatar!: string; data: Buffer;
userId: string;
@IsBoolean()
speaking!: boolean;
}
export class AudioMessage {
data!: Buffer;
userId!: string;
} }
export async function validateUserStateUpdate( export async function validateUserStateUpdate(
data: unknown, data: unknown,
): Promise<UserStateUpdate | null> { ): Promise<UserStateUpdate | null> {
if (typeof data !== "object" || data === null) { const result = userStateUpdateSchema.safeParse(data);
return null; return result.success ? result.data : null;
}
const obj = plainToClass(UserStateUpdate, data);
const errors = await validate(obj);
if (errors.length > 0) {
return null;
}
return obj;
} }

35
tests/validation.test.ts Normal file
View File

@@ -0,0 +1,35 @@
import { describe, expect, it } from "vitest";
import { validateUserStateUpdate } from "../src/validation";
describe("validateUserStateUpdate", () => {
it("returns typed data for a valid user state update", async () => {
const result = await validateUserStateUpdate({
userId: "123",
username: "aseph",
avatar: "https://example.invalid/avatar.png",
speaking: true,
});
expect(result).toEqual({
userId: "123",
username: "aseph",
avatar: "https://example.invalid/avatar.png",
speaking: true,
});
});
it("returns null for non-object input", async () => {
await expect(validateUserStateUpdate("bad")).resolves.toBeNull();
});
it("returns null for invalid field types", async () => {
const result = await validateUserStateUpdate({
userId: "123",
username: "aseph",
avatar: "https://example.invalid/avatar.png",
speaking: "true",
});
expect(result).toBeNull();
});
});