refactor(data): replace schema classes with readonly models

This commit is contained in:
2026-07-17 13:21:40 +08:00
parent 3437312167
commit ae97366a4a
103 changed files with 1220 additions and 2117 deletions
@@ -0,0 +1,84 @@
import { describe, expect, it } from "vitest";
import { FacebookIdentityResponseSchema } from "@/data/schemas/auth";
import { ChatHistoryResponseSchema } from "@/data/schemas/chat";
import { PaymentPlansResponseSchema } from "@/data/schemas/payment";
import { PrivateAlbumsResponseSchema } from "@/data/schemas/private-room";
import { UserSchema } from "@/data/schemas/user";
describe("immutable schemas", () => {
it("freezes nested user data", () => {
const user = UserSchema.parse({
id: "user-1",
username: "Ada",
personalityTraits: null,
});
expectDeepFrozen(user);
});
it("freezes chat history messages and payloads", () => {
const response = ChatHistoryResponseSchema.parse({
messages: [
{
id: "message-1",
role: "assistant",
content: "Hello",
image: { type: "jpg", url: "https://example.com/image.jpg" },
lockDetail: { locked: false, reason: null },
},
],
});
expectDeepFrozen(response);
});
it("freezes payment and private-room collections", () => {
const plans = PaymentPlansResponseSchema.parse({
firstRechargeOffer: {
enabled: true,
type: "half_price",
discountPercent: 50,
},
plans: [
{
planId: "vip_monthly",
planName: "Monthly VIP",
orderType: "vip_monthly",
creditBalance: 0,
amountCents: 999,
currency: "USD",
},
],
});
const albums = PrivateAlbumsResponseSchema.parse({
items: [
{
albumId: "album-1",
title: "Private album",
images: [{ url: "https://example.com/image.jpg", index: 0 }],
lockDetail: { locked: true },
},
],
});
expectDeepFrozen(plans);
expectDeepFrozen(albums);
});
it("freezes containers created from missing defaults", () => {
const response = FacebookIdentityResponseSchema.parse({});
expectDeepFrozen(response);
expect(response.facebookBinding).toEqual({ conflicts: [], bound: [] });
});
});
function expectDeepFrozen(value: unknown): void {
if (value === null || typeof value !== "object") return;
expect(Object.isFrozen(value)).toBe(true);
for (const child of Object.values(value)) {
expectDeepFrozen(child);
}
}