mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-07-14 14:57:00 +10:00
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/.
This commit is contained in:
@@ -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:*",
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
@@ -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<AIStoreState>) => void) => void;
|
||||
reset: () => void;
|
||||
};
|
||||
|
||||
type AIStore = AIStoreState & AIStoreActions;
|
||||
|
||||
const initialState: AIStoreState = {
|
||||
enabled: false,
|
||||
provider: "openai",
|
||||
model: "",
|
||||
apiKey: "",
|
||||
baseURL: "",
|
||||
testStatus: "unverified",
|
||||
};
|
||||
|
||||
export const useAIStore = create<AIStore>()(
|
||||
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,
|
||||
}),
|
||||
},
|
||||
),
|
||||
);
|
||||
Reference in New Issue
Block a user