import * as p from "@clack/prompts"; import type { StorageConfig } from "../config/schema.js"; import { resolveDefaultStorageDir, resolvePaperclipInstanceId } from "../config/home.js"; function defaultStorageBaseDir(): string { return resolveDefaultStorageDir(resolvePaperclipInstanceId()); } export function defaultStorageConfig(): StorageConfig { return { provider: "local_disk", localDisk: { baseDir: defaultStorageBaseDir(), }, s3: { bucket: "paperclip", region: "us-east-1", endpoint: undefined, prefix: "", forcePathStyle: false, }, }; } export async function promptStorage(current?: StorageConfig): Promise { const base = current ?? defaultStorageConfig(); const provider = await p.select({ message: "Storage provider", options: [ { value: "local_disk" as const, label: "Local disk (recommended)", hint: "best for single-user local deployments", }, { value: "s3" as const, label: "S3 compatible", hint: "for cloud/object storage backends", }, ], initialValue: base.provider, }); if (p.isCancel(provider)) { p.cancel("Setup cancelled."); process.exit(0); } if (provider === "local_disk") { const baseDir = await p.text({ message: "Local storage base directory", defaultValue: base.localDisk.baseDir || defaultStorageBaseDir(), placeholder: defaultStorageBaseDir(), validate: (value) => { if (!value || value.trim().length === 0) return "Storage base directory is required"; }, }); if (p.isCancel(baseDir)) { p.cancel("Setup cancelled."); process.exit(0); } return { provider: "local_disk", localDisk: { baseDir: baseDir.trim(), }, s3: base.s3, }; } const bucket = await p.text({ message: "S3 bucket", defaultValue: base.s3.bucket || "paperclip", placeholder: "paperclip", validate: (value) => { if (!value || value.trim().length === 0) return "Bucket is required"; }, }); if (p.isCancel(bucket)) { p.cancel("Setup cancelled."); process.exit(0); } const region = await p.text({ message: "S3 region", defaultValue: base.s3.region || "us-east-1", placeholder: "us-east-1", validate: (value) => { if (!value || value.trim().length === 0) return "Region is required"; }, }); if (p.isCancel(region)) { p.cancel("Setup cancelled."); process.exit(0); } const endpoint = await p.text({ message: "S3 endpoint (optional for compatible backends)", defaultValue: base.s3.endpoint ?? "", placeholder: "https://s3.amazonaws.com", }); if (p.isCancel(endpoint)) { p.cancel("Setup cancelled."); process.exit(0); } const prefix = await p.text({ message: "Object key prefix (optional)", defaultValue: base.s3.prefix ?? "", placeholder: "paperclip/", }); if (p.isCancel(prefix)) { p.cancel("Setup cancelled."); process.exit(0); } const forcePathStyle = await p.confirm({ message: "Use S3 path-style URLs?", initialValue: base.s3.forcePathStyle ?? false, }); if (p.isCancel(forcePathStyle)) { p.cancel("Setup cancelled."); process.exit(0); } return { provider: "s3", localDisk: base.localDisk, s3: { bucket: bucket.trim(), region: region.trim(), endpoint: endpoint.trim() || undefined, prefix: prefix.trim(), forcePathStyle, }, }; }