Effect Framework Integration
Relevant source files
The following files were used as context for generating this wiki page:
The putio-cli is built using the Effect ecosystem, a functional programming library for TypeScript that provides a powerful way to manage side effects, state, and concurrency. The project leverages various Effect-native patterns including Services, Layers, and the @effect/cli package for command-line parsing and execution.
This integration ensures that the CLI is deterministic, testable, and robust. By utilizing Effect.gen and services like CliRuntime, CliConfig, and CliState, the application maintains a clear separation between core logic and external environments (file systems, networks, or processes).
Sources: CLAUDE.md:20-23, src/cli.ts:133-140
Core Architecture and Services
The application architecture is centered around Context Services and Layers. Each major piece of functionality is encapsulated in a service that can be swapped out for testing or different environments.
Service Definitions
The CLI defines several key services using Context.Service:
| Service | Purpose | File Path |
|---|---|---|
CliRuntime | Provides access to platform-specific operations (Path, FS, Processes). | src/internal/runtime.ts |
CliConfig | Manages environment-based and explicit configurations. | src/internal/config.ts |
CliState | Handles persisted authentication state and profile management. | src/internal/state.ts |
CliSdk | Manages the put.io SDK instance and authentication context. | src/internal/sdk.ts |
Sources: src/internal/config.ts:46-48, src/internal/state.ts:114-116, src/internal/runtime.ts:25-27
Layered Dependency Injection
The project uses Layer to compose these services. For instance, CliConfigLive depends on CliRuntime to resolve file paths and environment variables.
The diagram shows the dependency flow where high-level services like CliState consume lower-level services like CliRuntime and CliConfig.
Sources: src/internal/config.ts:111, src/internal/state.ts:600, src/internal/state.test.ts:32-34
Command Execution Flow
The CLI uses @effect/cli (unstable) to define its command hierarchy. Every command is an Effect that operates within an environment containing the necessary services.
Logic Flow for Authenticated Commands
Most commands follow a standard flow: resolving output controls, authorizing the SDK, and executing the API call through a terminal loader.
The sequence diagram illustrates the lifecycle of a command execution, specifically how it retrieves auth state before making an SDK call.
Sources: src/internal/command.ts:474-486, src/commands/files.ts:153-162
Handling Pagination and Streaming
The integration includes specialized helpers like collectAllCursorPages and writeReadPages that use Effect's control flow to handle recursive API calls for pagination. These helpers can stream data as ndjson by yielding results as they arrive.
Sources: src/internal/command.ts:358-399, src/internal/command.ts:424-469
Error Handling and Validation
The project utilizes Data.TaggedError to create domain-specific errors that are compatible with Effect's error-tracking capabilities.
Key Error Types
- CliConfigError: Errors related to invalid environment variables or configuration schemas.
- AuthStateError: Errors arising from file system failures when reading config or invalid auth tokens.
- CliCommandInputError: Validation errors for user flags or JSON payloads.
Sources: src/internal/config.ts:42-44, src/internal/state.ts:68-70, src/internal/command.ts:131-133
Schema-based Validation
Effect's Schema library is used extensively for:
- Validation: Ensuring input flags match expected types (e.g.,
validateResourceIdentifier). - Decoding: Parsing JSON files or API responses into typed structures.
- Filtering: Using
Schema.makeFilterto reject unsafe strings like path traversal segments.
Sources: src/internal/command.ts:154-184, src/internal/config.ts:11-30
Conclusion
The integration of the Effect framework allows putio-cli to treat side effects as first-class citizens. By standardizing on services and layers, the codebase achieves high modularity, allowing developers to easily mock the environment during testing while maintaining a complex, asynchronous CLI surface.
Sources: CLAUDE.md:25-27, src/cli.ts:148-160