Something went wrong. Try again.
Something went wrong. Try again.
2.9 kB · 99 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100import { homedir } from "os";import { join } from "path";import { mkdir } from "fs/promises";
const CONFIG_DIR = join(homedir(), ".config", "tangled");const CONFIG_PATH = join(CONFIG_DIR, "config.json");
export interface Account { handle: string; did: string; pds: string; accessJwt: string; refreshJwt: string;}
export interface Config { current: string | null; accounts: Record<string, Account>; recentKnots: string[];}
const EMPTY: Config = { current: null, accounts: {}, recentKnots: [] };
export async function loadConfig(): Promise<Config> { const f = Bun.file(CONFIG_PATH); if (!(await f.exists())) return structuredClone(EMPTY); try { const data = await f.json(); return { ...EMPTY, ...data }; } catch { return structuredClone(EMPTY); }}
export async function saveConfig(cfg: Config): Promise<void> { await mkdir(CONFIG_DIR, { recursive: true, mode: 0o700 }); await Bun.write(CONFIG_PATH, JSON.stringify(cfg, null, 2)); await Bun.$`chmod 600 ${CONFIG_PATH}`.quiet();}
export async function setCurrent(did: string): Promise<void> { const cfg = await loadConfig(); if (!cfg.accounts[did]) throw new Error(`no account for ${did}`); cfg.current = did; await saveConfig(cfg);}
export async function upsertAccount(account: Account): Promise<void> { const cfg = await loadConfig(); cfg.accounts[account.did] = account; cfg.current = account.did; await saveConfig(cfg);}
export async function removeAccount(did: string): Promise<void> { const cfg = await loadConfig(); delete cfg.accounts[did]; if (cfg.current === did) { const remaining = Object.keys(cfg.accounts); cfg.current = remaining[0] ?? null; } await saveConfig(cfg);}
export async function getCurrentAccount(): Promise<Account | null> { const cfg = await loadConfig(); if (!cfg.current) return null; return cfg.accounts[cfg.current] ?? null;}
export async function requireCurrentAccount(): Promise<Account> { const a = await getCurrentAccount(); if (!a) throw new Error("not logged in — run `tangle auth login <handle>`"); return a;}
export async function findAccountByHandle(handle: string): Promise<Account | null> { const cfg = await loadConfig(); const normalized = handle.replace(/^@/, "").toLowerCase(); for (const a of Object.values(cfg.accounts)) { if (a.handle.toLowerCase() === normalized) return a; } return null;}
export async function rememberKnot(host: string): Promise<void> { const cfg = await loadConfig(); cfg.recentKnots = [host, ...cfg.recentKnots.filter((k) => k !== host)].slice(0, 10); await saveConfig(cfg);}
export async function updateTokens(did: string, accessJwt: string, refreshJwt: string): Promise<void> { const cfg = await loadConfig(); const a = cfg.accounts[did]; if (!a) return; a.accessJwt = accessJwt; a.refreshJwt = refreshJwt; await saveConfig(cfg);}