import { z } from "zod" import { fn } from "./util/fn" import { Actor } from "./actor" import { and, Database, eq, sql } from "./drizzle" import { Identifier } from "./identifier" import { KeyTable } from "./schema/key.sql" export namespace Key { export const list = async () => { const user = Actor.assert("user") const keys = await Database.use((tx) => tx .select({ id: KeyTable.id, name: KeyTable.name, key: KeyTable.key, userID: KeyTable.userID, timeCreated: KeyTable.timeCreated, timeUsed: KeyTable.timeUsed, }) .from(KeyTable) .where(eq(KeyTable.workspaceID, user.properties.workspaceID)) .orderBy(sql`${KeyTable.timeCreated} DESC`), ) return keys } export const create = fn(z.object({ name: z.string().min(1).max(255) }), async (input) => { const user = Actor.assert("user") const { name } = input // Generate secret key: sk- + 64 random characters (upper, lower, numbers) const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" let randomPart = "" for (let i = 0; i < 64; i++) { randomPart += chars.charAt(Math.floor(Math.random() * chars.length)) } const secretKey = `sk-${randomPart}` const keyID = Identifier.create("key") await Database.use((tx) => tx.insert(KeyTable).values({ id: keyID, workspaceID: user.properties.workspaceID, userID: user.properties.userID, name, key: secretKey, timeUsed: null, }), ) return keyID }) export const remove = fn(z.object({ id: z.string() }), async (input) => { const user = Actor.assert("user") await Database.use((tx) => tx.delete(KeyTable).where(and(eq(KeyTable.id, input.id), eq(KeyTable.workspaceID, user.properties.workspaceID))), ) }) }