From ca111d5ef09aa575673d9058434e71574c5928d9 Mon Sep 17 00:00:00 2001 From: Amruth Pillai Date: Wed, 13 May 2026 22:13:40 +0200 Subject: [PATCH] chore(ai): remove local AI store now that providers live server-side The Zustand-based useAIStore has been replaced by the server-side aiProviders oRPC router (encrypted credentials persisted in DB). Delete the dead store + tests, drop the ./store export, and remove zustand/immer deps which are no longer referenced anywhere in packages/ai/src/. --- packages/ai/package.json | 5 +- packages/ai/src/store.test.ts | 123 ---------------------------------- packages/ai/src/store.ts | 88 ------------------------ 3 files changed, 1 insertion(+), 215 deletions(-) delete mode 100644 packages/ai/src/store.test.ts delete mode 100644 packages/ai/src/store.ts diff --git a/packages/ai/package.json b/packages/ai/package.json index 635b03af4..9247aa7be 100644 --- a/packages/ai/package.json +++ b/packages/ai/package.json @@ -4,7 +4,6 @@ "type": "module", "private": true, "exports": { - "./store": "./src/store.ts", "./types": "./src/types.ts", "./prompts": "./src/prompts.ts", "./tools/patch-resume": "./src/tools/patch-resume.ts", @@ -24,10 +23,8 @@ "@reactive-resume/utils": "workspace:*", "deepmerge-ts": "^7.1.5", "fast-json-patch": "^3.1.1", - "immer": "^11.1.8", "jsonrepair": "^3.14.0", - "zod": "^4.4.3", - "zustand": "^5.0.13" + "zod": "^4.4.3" }, "devDependencies": { "@reactive-resume/config": "workspace:*", diff --git a/packages/ai/src/store.test.ts b/packages/ai/src/store.test.ts deleted file mode 100644 index 3155e96ce..000000000 --- a/packages/ai/src/store.test.ts +++ /dev/null @@ -1,123 +0,0 @@ -// @vitest-environment happy-dom - -import { afterEach, describe, expect, it } from "vitest"; -import { useAIStore } from "./store"; - -const reset = () => { - useAIStore.setState({ - enabled: false, - provider: "openai", - model: "", - apiKey: "", - baseURL: "", - testStatus: "unverified", - }); -}; - -afterEach(reset); - -describe("useAIStore", () => { - it("starts with provider=openai and disabled state", () => { - const state = useAIStore.getState(); - expect(state.enabled).toBe(false); - expect(state.provider).toBe("openai"); - expect(state.testStatus).toBe("unverified"); - }); - - it("set() updates fields and resets verification when credential fields change", () => { - useAIStore.setState({ testStatus: "success", enabled: true }); - - useAIStore.getState().set((draft) => { - draft.apiKey = "new-key"; - }); - - const state = useAIStore.getState(); - expect(state.apiKey).toBe("new-key"); - expect(state.testStatus).toBe("unverified"); - expect(state.enabled).toBe(false); - }); - - it("set() does NOT reset testStatus when changing non-credential fields", () => { - useAIStore.setState({ testStatus: "success", enabled: true }); - - useAIStore.getState().set((draft) => { - draft.testStatus = "success"; // explicit no-op - }); - - const state = useAIStore.getState(); - expect(state.testStatus).toBe("success"); - expect(state.enabled).toBe(true); - }); - - it("canEnable() is true only when testStatus is success", () => { - expect(useAIStore.getState().canEnable()).toBe(false); - - useAIStore.setState({ testStatus: "success" }); - expect(useAIStore.getState().canEnable()).toBe(true); - - useAIStore.setState({ testStatus: "failure" }); - expect(useAIStore.getState().canEnable()).toBe(false); - }); - - it("setEnabled(true) refuses to enable when testStatus is not success", () => { - useAIStore.getState().setEnabled(true); - expect(useAIStore.getState().enabled).toBe(false); - }); - - it("setEnabled(true) succeeds when testStatus is success", () => { - useAIStore.setState({ testStatus: "success" }); - useAIStore.getState().setEnabled(true); - expect(useAIStore.getState().enabled).toBe(true); - }); - - it("setEnabled(false) always succeeds (regardless of testStatus)", () => { - useAIStore.setState({ testStatus: "success", enabled: true }); - useAIStore.getState().setEnabled(false); - expect(useAIStore.getState().enabled).toBe(false); - }); - - it("reset() clears every field back to initial state", () => { - useAIStore.setState({ - enabled: true, - provider: "anthropic", - model: "claude-3", - apiKey: "key", - baseURL: "https://api.anthropic.com", - testStatus: "success", - }); - - useAIStore.getState().reset(); - - const state = useAIStore.getState(); - expect(state).toMatchObject({ - enabled: false, - provider: "openai", - model: "", - apiKey: "", - baseURL: "", - testStatus: "unverified", - }); - }); - - it("resets when only the provider changes", () => { - useAIStore.setState({ testStatus: "success", enabled: true }); - - useAIStore.getState().set((draft) => { - draft.provider = "gemini"; - }); - - expect(useAIStore.getState().testStatus).toBe("unverified"); - expect(useAIStore.getState().enabled).toBe(false); - }); - - it("resets when only the baseURL changes", () => { - useAIStore.setState({ testStatus: "success", enabled: true }); - - useAIStore.getState().set((draft) => { - draft.baseURL = "https://custom.example"; - }); - - expect(useAIStore.getState().testStatus).toBe("unverified"); - expect(useAIStore.getState().enabled).toBe(false); - }); -}); diff --git a/packages/ai/src/store.ts b/packages/ai/src/store.ts deleted file mode 100644 index 0171ab82f..000000000 --- a/packages/ai/src/store.ts +++ /dev/null @@ -1,88 +0,0 @@ -import type { WritableDraft } from "immer"; -import type { AIProvider } from "./types"; -import { createJSONStorage, persist } from "zustand/middleware"; -import { immer } from "zustand/middleware/immer"; -import { create } from "zustand/react"; - -type TestStatus = "unverified" | "success" | "failure"; - -type AIStoreState = { - enabled: boolean; - provider: AIProvider; - model: string; - apiKey: string; - baseURL: string; - testStatus: TestStatus; -}; - -type AIStoreActions = { - canEnable: () => boolean; - setEnabled: (value: boolean) => void; - set: (fn: (draft: WritableDraft) => void) => void; - reset: () => void; -}; - -type AIStore = AIStoreState & AIStoreActions; - -const initialState: AIStoreState = { - enabled: false, - provider: "openai", - model: "", - apiKey: "", - baseURL: "", - testStatus: "unverified", -}; - -export const useAIStore = create()( - persist( - immer((set, get) => ({ - ...initialState, - set: (fn) => { - set((draft) => { - const prev = { - provider: draft.provider, - model: draft.model, - apiKey: draft.apiKey, - baseURL: draft.baseURL, - }; - - fn(draft); - - if ( - draft.provider !== prev.provider || - draft.model !== prev.model || - draft.apiKey !== prev.apiKey || - draft.baseURL !== prev.baseURL - ) { - draft.testStatus = "unverified"; - draft.enabled = false; - } - }); - }, - reset: () => set(() => initialState), - canEnable: () => { - const { testStatus } = get(); - return testStatus === "success"; - }, - setEnabled: (value: boolean) => { - const canEnable = get().canEnable(); - if (value && !canEnable) return; - set((draft) => { - draft.enabled = value; - }); - }, - })), - { - name: "ai-store", - storage: createJSONStorage(() => localStorage), - partialize: (state) => ({ - enabled: state.enabled, - provider: state.provider, - model: state.model, - apiKey: state.apiKey, - baseURL: state.baseURL, - testStatus: state.testStatus, - }), - }, - ), -);