import type { SettingDeclaration } from "./src/pi-ext-settings.ts"; export interface S3Config { endpoint: string; bucket: string; region: string; accessKeyId: string; secretAccessKey: string; } export interface S3ConfigResolution { config?: S3Config; missing: string[]; } /** Non-secret S3 location; credentials stay env-only. */ export interface S3Location { endpoint?: string; bucket: string; region: string; } const DEFAULT_BUCKET = "pi-bak"; const DEFAULT_REGION = "auto"; function parseLocation(raw: unknown): string { const value = typeof raw === "string" ? raw.trim() : ""; if (!value) throw new Error("expected a non-empty string"); return value; } export const LOCATION_SETTINGS: { [K in keyof S3Location]-?: SettingDeclaration; } = { endpoint: { key: "bak.s3.endpoint", env: "PI_BAK_S3_ENDPOINT", parse: parseLocation, default: undefined, }, bucket: { key: "bak.s3.bucket", env: "PI_BAK_S3_BUCKET", parse: parseLocation, default: DEFAULT_BUCKET, }, region: { key: "bak.s3.region", env: "PI_BAK_S3_REGION", parse: parseLocation, default: DEFAULT_REGION, }, }; export function s3Config( env: NodeJS.ProcessEnv = process.env, location: S3Location = { endpoint: env.PI_BAK_S3_ENDPOINT?.trim(), bucket: env.PI_BAK_S3_BUCKET?.trim() || DEFAULT_BUCKET, region: env.PI_BAK_S3_REGION?.trim() || DEFAULT_REGION, }, ): S3ConfigResolution { const { endpoint } = location; const missing = [ ...(endpoint ? [] : ["PI_BAK_S3_ENDPOINT"]), ...( ["PI_BAK_S3_ACCESS_KEY_ID", "PI_BAK_S3_SECRET_ACCESS_KEY"] as const ).filter((name) => !env[name]?.trim()), ]; if (!endpoint || missing.length > 0) return { missing }; return { missing: [], config: { ...location, endpoint, accessKeyId: env.PI_BAK_S3_ACCESS_KEY_ID?.trim() ?? "", secretAccessKey: env.PI_BAK_S3_SECRET_ACCESS_KEY?.trim() ?? "", }, }; }