import { homedir } from 'node:os';
import { join } from 'node:path';
import { blankToUndef } from './types.js';
/**
* State-location overrides that influence where the CLI keeps its home
* directory and its two state files. A subset of the broader
* `ConnectionOverrides`, restated here so this module (the single source of
* truth for on-disk locations) has no runtime dependency on `config.ts`.
*/
export interface PathOverrides {
/** Explicit home root from the `--home` flag. Wins over `$BTCR2_HOME`. */
home? : string;
/** Explicit config-file path from the `--config` flag. Overrides the home default. */
config? : string;
/** Explicit keystore path from the `--keystore` flag. Overrides the home default. */
keystore? : string;
}
/** Environment variable naming the CLI home directory (all state colocated). */
export const ENV_HOME = 'BTCR2_HOME';
/** The config and keystore file names, kept side by side under the home root. */
export const CONFIG_FILENAME = 'config.json';
export const KEYSTORE_FILENAME = 'keystore.json';
/** The session file name, holding the unlock agent's cached passphrase (ADR 081). */
export const SESSION_FILENAME = 'session.json';
/**
* Resolves the CLI home directory: the single root that holds `config.json` and
* `keystore.json` side by side (ADR 079). Resolution order, highest wins:
*
* 1. `--home
` (the {@link PathOverrides.home} flag)
* 2. `$BTCR2_HOME`
* 3. the platform default (see {@link platformDefaultHome})
*
* A blank value at any layer defers to the next, mirroring the `blankToUndef`
* treatment every other precedence layer uses, so an exported-but-empty
* `BTCR2_HOME` does not resolve the home to a bare relative path.
*/
export function resolveHome(overrides?: PathOverrides): string {
return blankToUndef(overrides?.home)
?? blankToUndef(process.env[ENV_HOME])
?? platformDefaultHome();
}
/**
* The default home when no `--home` / `$BTCR2_HOME` override is present, chosen
* per OS so the location is idiomatic while staying a single colocated dir:
*
* - Windows: `%LOCALAPPDATA%\btcr2` (fallback `%APPDATA%\btcr2`, then the user
* profile), the native place for per-user application state.
* - Linux / macOS: `~/.btcr2`, the short, teachable dot-directory in the same
* family as `~/.ssh`, `~/.aws`, and `~/.gnupg`.
*/
export function platformDefaultHome(): string {
if (process.platform === 'win32') {
const base = blankToUndef(process.env.LOCALAPPDATA)
?? blankToUndef(process.env.APPDATA)
?? homedir();
return join(base, 'btcr2');
}
return join(homedir(), '.btcr2');
}
/**
* Default config-file path: `/config.json`. The `--config` flag, when
* present, overrides it wholesale (it names a specific file, not a home).
*/
export function defaultConfigPath(overrides?: PathOverrides): string {
return join(resolveHome(overrides), CONFIG_FILENAME);
}
/**
* Default keystore path: `/keystore.json`. The `--keystore` flag and a
* profile's `identity.keystore` (resolved in `config.ts`) override it; this
* function is the final fallback in that chain.
*/
export function defaultKeystorePath(overrides?: PathOverrides): string {
return join(resolveHome(overrides), KEYSTORE_FILENAME);
}
/**
* Session file path: `/session.json`, where the unlock agent caches the
* keystore passphrase (ADR 081). Deliberately derived from the home root alone,
* never from `--config` / `--keystore` or the config file, so `keystore lock`
* can revoke a session even under a malformed config, and so the read and write
* paths always agree on one location per home.
*/
export function defaultSessionPath(overrides?: PathOverrides): string {
return join(resolveHome(overrides), SESSION_FILENAME);
}