diff --git a/packages/lib/api.ts b/packages/lib/api.ts index 7cf8755f..e194cf9c 100644 --- a/packages/lib/api.ts +++ b/packages/lib/api.ts @@ -26,13 +26,14 @@ import { SearchResponseSchema, type SearchResult, SettingsRequestSchema, + SettingsResponseSchema, UpdateContainerTagSettingsRequestSchema, } from "../validation/api" const UpdateSettingsResponseSchema = z.object({ orgId: z.string(), orgSlug: z.string(), - updated: SettingsRequestSchema, + updated: SettingsResponseSchema, }) // Analytics request schema - custom to console @@ -190,7 +191,7 @@ export const apiSchema = createSchema({ // Settings operations "@get/settings": { - output: SettingsRequestSchema, + output: SettingsResponseSchema, }, "@patch/settings": { input: SettingsRequestSchema, diff --git a/packages/validation/api.test.ts b/packages/validation/api.test.ts index fa52ed89..404aa9c9 100644 --- a/packages/validation/api.test.ts +++ b/packages/validation/api.test.ts @@ -6,8 +6,42 @@ import { ListMemoriesQuerySchema, SearchRequestSchema, Searchv4RequestSchema, + SettingsRequestSchema, + SettingsResponseSchema, } from "./api" +describe("organization settings schemas", () => { + it.each([ + "x", + "x".repeat(750), + ])("accepts a filter prompt at a documented boundary", (filterPrompt) => { + expect(SettingsRequestSchema.parse({ filterPrompt }).filterPrompt).toBe( + filterPrompt, + ) + }) + + it.each([ + "", + "x".repeat(751), + ])("rejects a filter prompt outside the documented boundaries", (filterPrompt) => { + expect(SettingsRequestSchema.safeParse({ filterPrompt }).success).toBe( + false, + ) + }) + + it("accepts null to clear the filter prompt", () => { + expect( + SettingsRequestSchema.parse({ filterPrompt: null }).filterPrompt, + ).toBe(null) + }) + + it("continues to parse legacy empty prompts in settings responses", () => { + expect( + SettingsResponseSchema.parse({ filterPrompt: "" }).filterPrompt, + ).toBe("") + }) +}) + describe("search threshold schemas", () => { it("do not contain redundant number transforms or unreachable range guards", () => { const source = readFileSync(new URL("./api.ts", import.meta.url), "utf8") diff --git a/packages/validation/api.ts b/packages/validation/api.ts index ae6ac319..46ec196b 100644 --- a/packages/validation/api.ts +++ b/packages/validation/api.ts @@ -803,12 +803,16 @@ export const ErrorResponseSchema = z.object({ export type SearchResult = z.infer -export const SettingsRequestSchema = OrganizationSettingsSchema.omit({ +export const SettingsResponseSchema = OrganizationSettingsSchema.omit({ id: true, orgId: true, updatedAt: true, }).partial() +export const SettingsRequestSchema = SettingsResponseSchema.extend({ + filterPrompt: z.string().min(1).max(750).nullable().optional(), +}) + export const ConnectionResponseSchema = z.object({ createdAt: z.string().datetime(), documentLimit: z.number().optional(),