'init'
This commit is contained in:
40
app/lib/pocketbase/admin.ts
Normal file
40
app/lib/pocketbase/admin.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { getPocketBaseConfig } from "@/config/services.config";
|
||||
|
||||
let cachedToken: { token: string; expiresAt: number } | null = null;
|
||||
const TOKEN_TTL_MS = 10 * 60 * 1000;
|
||||
|
||||
export async function getAdminToken(): Promise<string | null> {
|
||||
if (cachedToken && Date.now() < cachedToken.expiresAt) {
|
||||
return cachedToken.token;
|
||||
}
|
||||
|
||||
const email = process.env.POCKETBASE_EMAIL;
|
||||
const password = process.env.POCKETBASE_PASSWORD;
|
||||
if (!email || !password) return null;
|
||||
|
||||
const pb = getPocketBaseConfig();
|
||||
const base = pb.url.replace(/\/$/, "");
|
||||
const body = JSON.stringify({ identity: email, password });
|
||||
const headers = { "Content-Type": "application/json" };
|
||||
|
||||
const endpoints = [
|
||||
`${base}/api/collections/_superusers/auth-with-password`,
|
||||
`${base}/api/admins/auth-with-password`,
|
||||
];
|
||||
|
||||
for (const url of endpoints) {
|
||||
try {
|
||||
const res = await fetch(url, { method: "POST", headers, body });
|
||||
if (!res.ok) continue;
|
||||
const data = await res.json();
|
||||
const token = data?.token;
|
||||
if (token) {
|
||||
cachedToken = { token, expiresAt: Date.now() + TOKEN_TTL_MS };
|
||||
return token;
|
||||
}
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
95
app/lib/pocketbase/auth.ts
Normal file
95
app/lib/pocketbase/auth.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import { getPocketBaseConfig } from "@/config/services.config";
|
||||
import { PB_STORAGE_KEYS } from "./constants";
|
||||
|
||||
export interface AuthUser {
|
||||
id: string;
|
||||
email: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface AuthResult {
|
||||
token: string;
|
||||
record: AuthUser;
|
||||
}
|
||||
|
||||
function getPBUrl(): string {
|
||||
return getPocketBaseConfig().url;
|
||||
}
|
||||
|
||||
export async function pbLogin(identity: string, password: string): Promise<AuthResult> {
|
||||
const res = await fetch(`${getPBUrl()}/api/collections/users/auth-with-password`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ identity, password }),
|
||||
});
|
||||
if (!res.ok) {
|
||||
const err = await res.json();
|
||||
throw new Error(err?.message || "登录失败");
|
||||
}
|
||||
const data = await res.json();
|
||||
if (!data?.token) throw new Error("登录响应异常");
|
||||
return { token: data.token, record: data.record };
|
||||
}
|
||||
|
||||
export async function pbRegister(
|
||||
email: string,
|
||||
password: string,
|
||||
passwordConfirm: string
|
||||
): Promise<AuthResult> {
|
||||
const config = getPocketBaseConfig();
|
||||
const res = await fetch(
|
||||
`${getPBUrl()}/api/collections/${config.usersCollection}/records`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ email, password, passwordConfirm }),
|
||||
}
|
||||
);
|
||||
if (!res.ok) {
|
||||
const err = await res.json();
|
||||
throw new Error(err?.message || "注册失败");
|
||||
}
|
||||
return pbLogin(email, password);
|
||||
}
|
||||
|
||||
export function pbSaveAuth(token: string, record: AuthUser): void {
|
||||
if (typeof window === "undefined") return;
|
||||
localStorage.setItem(PB_STORAGE_KEYS.token, token);
|
||||
localStorage.setItem(PB_STORAGE_KEYS.user, JSON.stringify(record));
|
||||
}
|
||||
|
||||
export async function pbLogout(): Promise<void> {
|
||||
if (typeof window === "undefined") return;
|
||||
localStorage.removeItem(PB_STORAGE_KEYS.token);
|
||||
localStorage.removeItem(PB_STORAGE_KEYS.user);
|
||||
localStorage.removeItem("join_pay_order");
|
||||
try {
|
||||
document.cookie = "join_pay_order=; path=/; max-age=0";
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
try {
|
||||
await fetch("/api/auth/logout", { method: "POST", credentials: "include" });
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
window.dispatchEvent(new CustomEvent("auth:updated"));
|
||||
}
|
||||
|
||||
export function getStoredUser(): AuthUser | null {
|
||||
if (typeof window === "undefined") return null;
|
||||
try {
|
||||
const raw = localStorage.getItem(PB_STORAGE_KEYS.user);
|
||||
if (!raw) return null;
|
||||
const user = JSON.parse(raw);
|
||||
if (!user?.id || !user?.email) return null;
|
||||
return user;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function getStoredToken(): string | null {
|
||||
if (typeof window === "undefined") return null;
|
||||
return localStorage.getItem(PB_STORAGE_KEYS.token);
|
||||
}
|
||||
2
app/lib/pocketbase/config.ts
Normal file
2
app/lib/pocketbase/config.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export { getPocketBaseConfig } from "@/config/services.config";
|
||||
export type { PocketBaseConfig } from "@/config/services.config";
|
||||
4
app/lib/pocketbase/constants.ts
Normal file
4
app/lib/pocketbase/constants.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export const PB_STORAGE_KEYS = {
|
||||
token: "pb_token",
|
||||
user: "pb_user",
|
||||
} as const;
|
||||
11
app/lib/pocketbase/index.ts
Normal file
11
app/lib/pocketbase/index.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export {
|
||||
pbLogin,
|
||||
pbRegister,
|
||||
pbSaveAuth,
|
||||
pbLogout,
|
||||
getStoredUser,
|
||||
getStoredToken,
|
||||
} from "./auth";
|
||||
export type { AuthUser, AuthResult } from "./auth";
|
||||
export { PB_STORAGE_KEYS } from "./constants";
|
||||
export { getPocketBaseConfig } from "./config";
|
||||
Reference in New Issue
Block a user