kioai / artifacts /api-server /src /routes /accounts.ts
kinaiok
Initial deployment setup for Hugging Face Spaces
5ef6e9d
import { Router } from "express";
import { db, geminiAccountsTable } from "@workspace/db";
import { eq, desc } from "drizzle-orm";
import { requireAdmin } from "./admin";
import { requireJwtAuth } from "./auth";
const router = Router();
router.use(requireJwtAuth);
router.get("/", requireAdmin, async (_req, res) => {
const rows = await db
.select()
.from(geminiAccountsTable)
.orderBy(desc(geminiAccountsTable.createdAt));
res.json(
rows.map((r) => ({
id: r.id,
label: r.label,
tokenPreview: r.bearerToken ? r.bearerToken.substring(0, 12) + "..." : null,
hasRefreshToken: !!r.refreshToken,
isActive: r.isActive,
lastUsedAt: r.lastUsedAt?.toISOString() ?? null,
createdAt: r.createdAt.toISOString(),
}))
);
});
router.post("/", requireAdmin, async (req, res) => {
const { label, bearerToken, refreshToken } = req.body as {
label?: string;
bearerToken?: string;
refreshToken?: string;
};
if (!bearerToken?.trim()) {
return res.status(400).json({ error: "bearerToken is required" });
}
const [inserted] = await db
.insert(geminiAccountsTable)
.values({
label: (label || "帳戶").trim(),
bearerToken: bearerToken.trim(),
refreshToken: refreshToken?.trim() || null,
isActive: true,
})
.returning();
res.json({
id: inserted.id,
label: inserted.label,
tokenPreview: inserted.bearerToken.substring(0, 12) + "...",
isActive: inserted.isActive,
createdAt: inserted.createdAt.toISOString(),
});
});
router.patch("/:id/label", requireAdmin, async (req, res) => {
const id = Number(req.params.id);
const { label } = req.body as { label?: string };
if (!label?.trim()) return res.status(400).json({ error: "label is required" });
await db.update(geminiAccountsTable).set({ label: label.trim() }).where(eq(geminiAccountsTable.id, id));
res.json({ success: true });
});
router.patch("/:id/toggle", requireAdmin, async (req, res) => {
const id = Number(req.params.id);
const rows = await db.select().from(geminiAccountsTable).where(eq(geminiAccountsTable.id, id)).limit(1);
if (!rows.length) return res.status(404).json({ error: "Account not found" });
const newActive = !rows[0].isActive;
await db.update(geminiAccountsTable).set({ isActive: newActive }).where(eq(geminiAccountsTable.id, id));
res.json({ success: true, isActive: newActive });
});
router.delete("/:id", requireAdmin, async (req, res) => {
const id = Number(req.params.id);
await db.delete(geminiAccountsTable).where(eq(geminiAccountsTable.id, id));
res.json({ success: true });
});
export default router;