Files
kuber/command/db.ts
T
2026-10-07 10:33:21 +00:00

101 lines
2.4 KiB
TypeScript

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 = <T>(
path: string,
init?: ApiRequestInit,
) => Promise<T>;
export function getDatabaseCredentials(
project: string,
claim: PostgresClaim,
request: DbApiRequest = apiRequest,
): Promise<RoleCredentials> {
return request<RoleCredentials>(
`/workspaces/${encodeURIComponent(project)}/databases/credentials`,
{ method: "POST", json: { claim } },
);
}
const list = defineCommand({
meta: {
name: "ls",
description: "List database volumes used by this project",
},
async run() {
const claims = getComposePostgresClaims(await ctx().compose());
if (claims.length === 0) {
console.log("No database 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 database 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 database 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: "View project databases and credentials",
},
subCommands: {
creds,
ls: list,
},
});