diff --git a/src/actions/housekeeping-preferences.test.ts b/src/actions/housekeeping-preferences.test.ts index 767ad753..1f34c2b6 100644 --- a/src/actions/housekeeping-preferences.test.ts +++ b/src/actions/housekeeping-preferences.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, expect, it, vi } from "vitest"; +import { beforeEach, describe, expect, expectTypeOf, it, vi } from "vitest"; vi.mock("@/features/housekeeping/foundation/server-capability-context", () => ({ getHousekeepingCapabilityContext: vi.fn(), @@ -40,6 +40,15 @@ describe("housekeeping preference actions", () => { expect(saveHousekeepingPreferences).toHaveLength(1); }); + it("publishes exact action signatures without caller-controlled dependencies", () => { + expectTypeOf< + Parameters + >().toEqualTypeOf<[]>(); + expectTypeOf< + Parameters + >().toEqualTypeOf<[input: unknown]>(); + }); + it("derives the read owner from the server capability context", async () => { const result = await loadHousekeepingPreferences(); diff --git a/src/features/housekeeping/foundation/preferences/schema.test.ts b/src/features/housekeeping/foundation/preferences/schema.test.ts index 8067ce16..7c9687dd 100644 --- a/src/features/housekeeping/foundation/preferences/schema.test.ts +++ b/src/features/housekeeping/foundation/preferences/schema.test.ts @@ -71,4 +71,21 @@ describe("housekeeping preferences schema", () => { }).success, ).toBe(false); }); + + it("rejects a Unicode payload whose UTF-8 bytes exceed the 4096-byte limit", () => { + const value = { + ...defaultHousekeepingPreferences(), + pinnedRouteIds: Array.from( + { length: 29 }, + (_, index) => `${index.toString().padStart(3, "0")}${"é".repeat(125)}`, + ), + }; + const serialized = JSON.stringify(value); + + expect(serialized.length).toBeLessThanOrEqual(4096); + expect(new TextEncoder().encode(serialized).byteLength).toBeGreaterThan( + 4096, + ); + expect(housekeepingPreferencesSchema.safeParse(value).success).toBe(false); + }); }); diff --git a/src/features/housekeeping/foundation/preferences/schema.ts b/src/features/housekeeping/foundation/preferences/schema.ts index 0bed8f8f..f1dba0df 100644 --- a/src/features/housekeeping/foundation/preferences/schema.ts +++ b/src/features/housekeeping/foundation/preferences/schema.ts @@ -45,7 +45,7 @@ export const housekeepingPreferencesSchema: z.ZodType = .strict() .superRefine((preferences, context) => { if ( - JSON.stringify(preferences).length > + new TextEncoder().encode(JSON.stringify(preferences)).byteLength > HOUSEKEEPING_PREFERENCE_MAX_SERIALIZED_BYTES ) { context.addIssue({