feat(cli): add client commands and home-based local runtime defaults
This commit is contained in:
@@ -3,6 +3,11 @@ import { existsSync } from "node:fs";
|
||||
import { config as loadDotenv } from "dotenv";
|
||||
import { resolvePaperclipEnvPath } from "./paths.js";
|
||||
import { SECRET_PROVIDERS, type SecretProvider } from "@paperclip/shared";
|
||||
import {
|
||||
resolveDefaultEmbeddedPostgresDir,
|
||||
resolveDefaultSecretsKeyFilePath,
|
||||
resolveHomeAwarePath,
|
||||
} from "./home-paths.js";
|
||||
|
||||
const PAPERCLIP_ENV_FILE_PATH = resolvePaperclipEnvPath();
|
||||
if (existsSync(PAPERCLIP_ENV_FILE_PATH)) {
|
||||
@@ -54,7 +59,9 @@ export function loadConfig(): Config {
|
||||
port: Number(process.env.PORT) || fileConfig?.server.port || 3100,
|
||||
databaseMode: fileDatabaseMode,
|
||||
databaseUrl: process.env.DATABASE_URL ?? fileDbUrl,
|
||||
embeddedPostgresDataDir: fileConfig?.database.embeddedPostgresDataDir ?? "./data/embedded-postgres",
|
||||
embeddedPostgresDataDir: resolveHomeAwarePath(
|
||||
fileConfig?.database.embeddedPostgresDataDir ?? resolveDefaultEmbeddedPostgresDir(),
|
||||
),
|
||||
embeddedPostgresPort: fileConfig?.database.embeddedPostgresPort ?? 54329,
|
||||
serveUi:
|
||||
process.env.SERVE_UI !== undefined
|
||||
@@ -64,9 +71,11 @@ export function loadConfig(): Config {
|
||||
secretsProvider,
|
||||
secretsStrictMode,
|
||||
secretsMasterKeyFilePath:
|
||||
process.env.PAPERCLIP_SECRETS_MASTER_KEY_FILE ??
|
||||
fileSecrets?.localEncrypted.keyFilePath ??
|
||||
"./data/secrets/master.key",
|
||||
resolveHomeAwarePath(
|
||||
process.env.PAPERCLIP_SECRETS_MASTER_KEY_FILE ??
|
||||
fileSecrets?.localEncrypted.keyFilePath ??
|
||||
resolveDefaultSecretsKeyFilePath(),
|
||||
),
|
||||
heartbeatSchedulerEnabled: process.env.HEARTBEAT_SCHEDULER_ENABLED !== "false",
|
||||
heartbeatSchedulerIntervalMs: Math.max(10000, Number(process.env.HEARTBEAT_SCHEDULER_INTERVAL_MS) || 30000),
|
||||
};
|
||||
|
||||
49
server/src/home-paths.ts
Normal file
49
server/src/home-paths.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
|
||||
const DEFAULT_INSTANCE_ID = "default";
|
||||
const INSTANCE_ID_RE = /^[a-zA-Z0-9_-]+$/;
|
||||
|
||||
function expandHomePrefix(value: string): string {
|
||||
if (value === "~") return os.homedir();
|
||||
if (value.startsWith("~/")) return path.resolve(os.homedir(), value.slice(2));
|
||||
return value;
|
||||
}
|
||||
|
||||
export function resolvePaperclipHomeDir(): string {
|
||||
const envHome = process.env.PAPERCLIP_HOME?.trim();
|
||||
if (envHome) return path.resolve(expandHomePrefix(envHome));
|
||||
return path.resolve(os.homedir(), ".paperclip");
|
||||
}
|
||||
|
||||
export function resolvePaperclipInstanceId(): string {
|
||||
const raw = process.env.PAPERCLIP_INSTANCE_ID?.trim() || DEFAULT_INSTANCE_ID;
|
||||
if (!INSTANCE_ID_RE.test(raw)) {
|
||||
throw new Error(`Invalid PAPERCLIP_INSTANCE_ID '${raw}'.`);
|
||||
}
|
||||
return raw;
|
||||
}
|
||||
|
||||
export function resolvePaperclipInstanceRoot(): string {
|
||||
return path.resolve(resolvePaperclipHomeDir(), "instances", resolvePaperclipInstanceId());
|
||||
}
|
||||
|
||||
export function resolveDefaultConfigPath(): string {
|
||||
return path.resolve(resolvePaperclipInstanceRoot(), "config.json");
|
||||
}
|
||||
|
||||
export function resolveDefaultEmbeddedPostgresDir(): string {
|
||||
return path.resolve(resolvePaperclipInstanceRoot(), "db");
|
||||
}
|
||||
|
||||
export function resolveDefaultLogsDir(): string {
|
||||
return path.resolve(resolvePaperclipInstanceRoot(), "logs");
|
||||
}
|
||||
|
||||
export function resolveDefaultSecretsKeyFilePath(): string {
|
||||
return path.resolve(resolvePaperclipInstanceRoot(), "secrets", "master.key");
|
||||
}
|
||||
|
||||
export function resolveHomeAwarePath(value: string): string {
|
||||
return path.resolve(expandHomePrefix(value));
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { resolveDefaultConfigPath } from "./home-paths.js";
|
||||
|
||||
const PAPERCLIP_CONFIG_BASENAME = "config.json";
|
||||
const PAPERCLIP_ENV_FILENAME = ".env";
|
||||
@@ -25,7 +26,7 @@ function findConfigFileFromAncestors(startDir: string): string | null {
|
||||
export function resolvePaperclipConfigPath(overridePath?: string): string {
|
||||
if (overridePath) return path.resolve(overridePath);
|
||||
if (process.env.PAPERCLIP_CONFIG) return path.resolve(process.env.PAPERCLIP_CONFIG);
|
||||
return findConfigFileFromAncestors(process.cwd()) ?? path.resolve(process.cwd(), ".paperclip", PAPERCLIP_CONFIG_BASENAME);
|
||||
return findConfigFileFromAncestors(process.cwd()) ?? resolveDefaultConfigPath();
|
||||
}
|
||||
|
||||
export function resolvePaperclipEnvPath(overrideConfigPath?: string): string {
|
||||
|
||||
Reference in New Issue
Block a user