import path from "path" import { Global } from "../global" import z from "zod" import { Filesystem } from "../util/filesystem" export const OAUTH_DUMMY_KEY = "opencode-oauth-dummy-key" export namespace Auth { export const Oauth = z .object({ type: z.literal("oauth"), refresh: z.string(), access: z.string(), expires: z.number(), accountId: z.string().optional(), enterpriseUrl: z.string().optional(), }) .meta({ ref: "OAuth" }) export const Api = z .object({ type: z.literal("api"), key: z.string(), }) .meta({ ref: "ApiAuth" }) export const WellKnown = z .object({ type: z.literal("wellknown"), key: z.string(), token: z.string(), }) .meta({ ref: "WellKnownAuth" }) export const Info = z.discriminatedUnion("type", [Oauth, Api, WellKnown]).meta({ ref: "Auth" }) export type Info = z.infer const filepath = path.join(Global.Path.data, "auth.json") export async function get(providerID: string) { const auth = await all() return auth[providerID] } export async function all(): Promise> { const data = await Filesystem.readJson>(filepath).catch(() => ({})) return Object.entries(data).reduce( (acc, [key, value]) => { const parsed = Info.safeParse(value) if (!parsed.success) return acc acc[key] = parsed.data return acc }, {} as Record, ) } export async function set(key: string, info: Info) { const normalized = key.replace(/\/+$/, "") const data = await all() if (normalized !== key) delete data[key] delete data[normalized + "/"] await Filesystem.writeJson(filepath, { ...data, [normalized]: info }, 0o600) } export async function remove(key: string) { const normalized = key.replace(/\/+$/, "") const data = await all() delete data[key] delete data[normalized] await Filesystem.writeJson(filepath, data, 0o600) } }