import { defineCommand } from "citty"; import { apiRequest, type ApiRequestInit } from "../lib/api"; import { ctx } from "../lib/context"; import { DATABASE_HOST, DATABASE_PORT, buildDatabaseUrl, getComposePostgresClaims, type PostgresClaim, type RoleCredentials, } from "../lib/database"; import { toTable } from "../lib/format"; export type DbApiRequest = ( path: string, init?: ApiRequestInit, ) => Promise; export function getDatabaseCredentials( project: string, claim: PostgresClaim, request: DbApiRequest = apiRequest, ): Promise { return request( `/workspaces/${encodeURIComponent(project)}/databases/credentials`, { method: "POST", json: { claim } }, ); } const list = defineCommand({ meta: { name: "ls", description: "List managed postgres claims", }, async run() { const claims = getComposePostgresClaims(await ctx().compose()); if (claims.length === 0) { console.log("No managed postgres volumes declared"); return; } console.log( toTable( claims.map((claim) => ({ service: claim.service, username: claim.username, database: claim.database, secret: claim.secretName, })), ), ); }, }); const creds = defineCommand({ meta: { name: "creds", description: "Print postgres credentials for a service", }, async run({ args }) { const service = args._[0]; if (!service) throw new Error("Service name is required"); const context = ctx(); const claim = getComposePostgresClaims(await context.compose()).find( (entry) => entry.service === service, ); if (!claim) { throw new Error( `Service ${service} does not declare a managed postgres volume.`, ); } const credentials = await getDatabaseCredentials(context.project, claim); const url = buildDatabaseUrl(claim, credentials); console.log( toTable([ { service: claim.service, username: credentials.username, database: claim.database, host: DATABASE_HOST, port: DATABASE_PORT, secret: claim.secretName, }, ]), ); console.log(`DATABASE_URL=${url}`); }, }); export const db = defineCommand({ meta: { name: "db", description: "Inspect managed postgres databases", }, subCommands: { creds, ls: list, }, });