import type { Selectable } from 'kysely' import type * as Db from '../Db.js' import type * as db_Schema from '../Schema.js' /** Columns of the `billing_settings` table, derived from `Schema.BillingSettings`. */ export type Table = db_Schema.BillingSettings /** A stored billing-settings row. */ export type Record = Selectable /** Currencies limits may be denominated in; single-member today, widens without schema changes. */ export const currencies = ['usd'] as const satisfies readonly Record['currency'][] /** Spend-limit windows; single-member today, widens without schema changes. */ export const periods = ['month'] as const satisfies readonly Record['period'][] /** * Reads an organization's billing settings. * * @param db - The database. * @param orgId - The organization id (`org_…`). * @param environment - The environment to read; defaults to `production`. * @returns The stored record, or `undefined` when the org has none. */ export function get( db: Db.Db, orgId: string, environment: Record['environment'] = 'production', ): Promise { return db.kysely .selectFrom('billing_settings') .selectAll() .where('orgId', '=', orgId) .where('environment', '=', environment) .executeTakeFirst() } /** * Upserts an organization's billing settings with PATCH semantics: absent * fields keep their stored value, `null` clears the limit. * * @param db - The database. * @param input - The settings to apply. * @returns The stored record. */ export async function upsert(db: Db.Db, input: upsert.Input): Promise { const now = new Date().toISOString() const environment = input.environment ?? 'production' return await db.kysely .insertInto('billing_settings') .values({ createdAt: now, currency: input.currency ?? 'usd', environment, orgId: input.orgId, period: input.period ?? 'month', spendLimit: input.spendLimit ?? null, txFeeLimit: input.txFeeLimit ?? null, updatedAt: now, }) // Targets the `(org_id, environment)` unique index, which exists both // before and after the org pkey drop release. .onConflict((oc) => oc.columns(['orgId', 'environment']).doUpdateSet({ ...(input.currency !== undefined ? { currency: input.currency } : {}), ...(input.period !== undefined ? { period: input.period } : {}), ...(input.spendLimit !== undefined ? { spendLimit: input.spendLimit } : {}), ...(input.txFeeLimit !== undefined ? { txFeeLimit: input.txFeeLimit } : {}), updatedAt: now, }), ) .returningAll() .executeTakeFirstOrThrow() } export declare namespace upsert { /** Fields accepted when upserting billing settings; absent = unchanged, null = cleared. */ type Input = { /** Currency both limits are denominated in. */ currency?: Record['currency'] | undefined /** Environment these settings apply to; defaults to `production`. */ environment?: Record['environment'] | undefined /** Organization id (`org_…`) the settings belong to. */ orgId: string /** Spend-limit window. */ period?: Record['period'] | undefined /** Spend limit per period (decimal string in `currency` units), or null to clear. */ spendLimit?: string | null | undefined /** Per-transaction fee cap (decimal string in `currency` units), or null to clear. */ txFeeLimit?: string | null | undefined } } /** * Deletes an organization's billing settings. * * @param db - The database. * @param orgId - The organization id (`org_…`). * @returns Whether a settings row existed and was deleted. */ export async function deleteByOrg(db: Db.Db, orgId: string): Promise { const result = await db.kysely .deleteFrom('billing_settings') .where('orgId', '=', orgId) .executeTakeFirst() return result.numDeletedRows > 0n }