Add Convex client setup and authentication handling

- Introduced a new module for Convex client configuration in `src/modules/convex.ts`.
- Implemented an authentication token fetcher to manage user tokens.
- Integrated the Convex client into the AuthProvider component in `src/pages/auth/index.tsx`.
This commit is contained in:
2026-03-06 19:00:24 +08:00
parent 700f8177fe
commit 91abdac399
5 changed files with 575 additions and 22 deletions

View File

@@ -26,6 +26,7 @@
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
"convex": "^1.32.0",
"dayjs": "^1.11.19",
"es-toolkit": "^1.45.1",
"fuse.js": "^7.1.0",
@@ -42,6 +43,7 @@
"access": "public"
},
"devDependencies": {
"@kevisual/convex": "^0.0.5",
"@kevisual/kv-login": "^0.1.17",
"@kevisual/query": "0.0.52",
"@kevisual/types": "^0.0.12",
@@ -49,7 +51,7 @@
"@tailwindcss/vite": "^4.2.1",
"@tanstack/react-router-devtools": "^1.166.2",
"@tanstack/router-plugin": "^1.166.2",
"@types/node": "^25.3.3",
"@types/node": "^25.3.5",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.1.4",

556
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -24,10 +24,11 @@
"AGENTS.md": "https://kevisual.cn/root/ai/kevisual/frontend/vite-react-template/AGENTS.md",
"vite.config.ts": "https://kevisual.cn/root/ai/kevisual/frontend/vite-react-template/vite.config.ts",
"src/main.tsx": "https://kevisual.cn/root/ai/kevisual/frontend/vite-react-template/src/main.tsx",
"public/auth.json": "https://kevisual.cn/root/ai/kevisual/frontend/vite-react-template/public/auth.json",
"src/agents/index.ts": "https://kevisual.cn/root/ai/kevisual/frontend/vite-react-template/src/agents/index.ts",
"src/modules/basename.ts": "https://kevisual.cn/root/ai/kevisual/frontend/vite-react-template/src/modules/basename.ts",
"src/modules/query.ts": "https://kevisual.cn/root/ai/kevisual/frontend/vite-react-template/src/modules/query.ts",
"src/routes/__root.tsx": "https://kevisual.cn/root/ai/kevisual/frontend/vite-react-template/src/routes/__root.tsx",
"src/modules/convex.ts": "https://kevisual.cn/root/ai/kevisual/frontend/vite-react-template/src/modules/convex.ts",
"src/routes/demo.tsx": "https://kevisual.cn/root/ai/kevisual/frontend/vite-react-template/src/routes/demo.tsx",
"src/routes/index.tsx": "https://kevisual.cn/root/ai/kevisual/frontend/vite-react-template/src/routes/index.tsx",
"src/routes/login.tsx": "https://kevisual.cn/root/ai/kevisual/frontend/vite-react-template/src/routes/login.tsx",

32
src/modules/convex.ts Normal file
View File

@@ -0,0 +1,32 @@
import { api } from "@kevisual/convex";
import { ConvexClient, AuthTokenFetcher, ConvexHttpClient } from "convex/browser";
const url = localStorage.getItem("CONVEX_URL") || 'https://convex.kevisual.cn'
const client = new ConvexClient(url!);
const httpClient = new ConvexHttpClient(url!);
export const initConvex = async () => {
const getToken = async () => {
const token = localStorage.getItem("token");
if (!token) {
return null;
}
const res = await httpClient.action(api.token.create, { token: token! });
if (res.code === 200) {
return res.data.accessToken;
}
return null;
}
const authTokenFetcher: AuthTokenFetcher = async ({ forceRefreshToken }: { forceRefreshToken: boolean }) => {
console.log("AuthTokenFetcher called, forceRefreshToken:", forceRefreshToken);
if (forceRefreshToken) {
const token = await getToken();
// console.log("fetch got token:", token);
return token;
}
return null;
}
client.setAuth(authTokenFetcher, (isAuthenticated) => {
console.log("Auth isAuthenticated:", isAuthenticated);
});
}
export { client, httpClient };

View File

@@ -5,6 +5,7 @@ import { LogIn, LockKeyhole } from "lucide-react"
export { BaseHeader } from './modules/BaseHeader'
import { useMemo } from 'react';
import { useLocation, useNavigate } from '@tanstack/react-router';
import { initConvex } from "@/modules/convex";
type Props = {
children?: React.ReactNode,
@@ -18,6 +19,7 @@ export const AuthProvider = ({ children, mustLogin }: Props) => {
})));
useEffect(() => {
store.init()
initConvex();
}, [])
const location = useLocation()
const navigate = useNavigate();