Application State Management
Relevant source files
The following files were used as context for generating this wiki page:
Application state management in the putio-cli project is centered around the persistence and resolution of authentication credentials, configuration settings, and named user profiles. The system ensures that the CLI can operate in various environments—ranging from interactive human sessions to headless automated agents—by implementing a deterministic resolution hierarchy for state data.
The core of this system is the CliState service, which leverages the Effect library to provide a functional and type-safe interface for interacting with the filesystem and environment variables. This system manages the lifecycle of the configuration file, typically stored in JSON format, and handles complex logic such as profile switching, token redaction, and schema validation.
Sources: src/internal/state.ts:1-125, README.md:126-150
State Data Architecture
The application state is primarily represented by the PutioCliConfig schema. This structure stores the global API base URL, an optional legacy authentication token, a default profile pointer, and a dictionary of named profiles.
Configuration Schema
The system uses the effect/Schema library to enforce strict data modeling for persisted state.
| Field | Type | Description |
|---|---|---|
api_base_url | NonEmptyString | The base URL for the put.io API. Defaults to the official API. |
auth_token | String (Optional) | Legacy single-token storage for simple configurations. |
default_profile | String (Optional) | The name of the profile to use if none is explicitly specified. |
profiles | Record<String, ProfileConfig> | A collection of named profiles with unique tokens and URLs. |
Sources: src/internal/state.ts:15-31, src/internal/metadata.test.ts:147-160
Profile Configuration
Each profile in the profiles record can override the global API base URL and contains its own auth_token.
export const PutioCliProfileConfigSchema = Schema.Struct({
api_base_url: Schema.optional(NonEmptyStringSchema),
auth_token: Schema.optional(NonEmptyStringSchema),
});
Sources: src/internal/state.ts:15-20
Auth State Resolution Logic
The CLI resolves the active state (token and API URL) using a specific precedence. Environment variables always take the highest priority, followed by explicit command-line flags, and finally the persisted configuration file.
Resolution Precedence
The following diagram illustrates the flow of resolving the ResolvedAuthState used by the SDK.
A brief sentence explaining what the diagram shows: This flowchart depicts the deterministic order in which the CLI searches for authentication credentials across environment variables, profiles, and configuration files.
Sources: src/internal/state.ts:397-458, README.md:126-135
Key Resolution Components
- Environment Variables:
PUTIO_CLI_TOKENoverrides all persisted state.PUTIO_CLI_PROFILEselects a specific profile. - Runtime Config: Resolved via
resolveCliRuntimeConfig, providing the path to the configuration file (typically viaXDG_CONFIG_HOMEor a default hidden directory). - Validation: Profile names are validated against a specific pattern (alphanumeric, dots, underscores, hyphens) before use.
Sources: src/internal/state.ts:156-170, src/internal/state.test.ts:50-75
Persistent Storage Management
The CliStateService handles the reading and writing of the state to the local filesystem. To ensure security, configuration files are created and modified with private permissions (0o600).
File Operations
The system ensures that the directory structure exists before writing and performs atomic updates to the JSON file. If a configuration is cleared to its default state, the system automatically removes the physical file to keep the user's filesystem clean.
A brief sentence explaining what the diagram shows: This sequence diagram illustrates the lifecycle of a state update, including directory creation and permission enforcement.
Sources: src/internal/state.ts:219-250, src/internal/state.test.ts:77-105
Critical Functions in state.ts
| Function | Purpose |
|---|---|
loadPersistedState | Reads and validates the JSON config from disk. |
savePersistedState | Updates a token/URL for a profile or the global config. |
resolveAuthState | Returns the final token and URL based on precedence rules. |
useProfile | Sets the default_profile field in the configuration. |
clearPersistedState | Redacts tokens from the config or specific profiles. |
Sources: src/internal/state.ts:79-125
Mutation State and Dry Runs
For operations that modify state on the remote API (writes), the system provides a "Dry Run" mechanism. This allows users to preview the state changes and request payloads without executing the actual mutation.
The resolveMutationInput function facilitates this by either building input from command-line flags or decoding a raw JSON input provided via the --json flag. If dry-run is active, the writeDryRunPlan function intercepts the flow to output the intended request state instead of passing it to the SDK.
Sources: src/internal/command.ts:468-485, src/commands/files.ts:252-258
Security and Redaction
The state management system includes built-in safeguards to prevent the accidental exposure of sensitive information (tokens and passwords) during logging or terminal output.
The output-service.js contains a sanitizeTerminalValue function that recursively scans objects for sensitive keys (e.g., auth_token, password, token) and replaces their values with [REDACTED]. This is applied to all state data before it is rendered to the terminal or provided in describe metadata.
Sources: src/internal/output-service.js, src/internal/output.test.ts:20-45, src/internal/state.test.ts:162-185
Conclusion
State management in the putio-cli is a robust system that prioritizes security and deterministic behavior. By combining a layered resolution strategy with strict schema validation and automated filesystem management, it provides a stable foundation for both human users and automated agents to interact with the put.io API.