Metadata-Version: 2.4
Name: stashkat
Version: 0.1.2
Summary: Pluggable S3 storage and fetcher for CoreKat
Author-email: velocikat <velocikat@lza.sh>
Requires-Python: >=3.12
Requires-Dist: aioboto3>=12.0
Requires-Dist: corekat[cli]>=0.1.0
Provides-Extra: all
Requires-Dist: corekat[sentry]; extra == 'all'
Provides-Extra: sentry
Requires-Dist: corekat[sentry]; extra == 'sentry'
Description-Content-Type: text/markdown


# StashKat

`stashkat` provides a pluggable S3 storage backend for `corekat`. It implements the `Fetcher` protocol, allowing `corekat`'s `DownloadClient` to handle `s3://` URLs. It also provides a CLI for direct S3 operations.

## Features

- **S3 Fetcher for CoreKat**: Enables `corekat.client.filedl.DownloadClient` to download from S3.
- **Async-first S3 Client**: A high-level, asynchronous client for interacting with S3-compatible object storage.
- **Command-Line Interface**: `stashkat` CLI for uploading, downloading, and copying files from S3.

## Installation

```bash
uv pip install stashkat
```

## Integration with CoreKat

When `stashkat` is installed in the same environment as `corekat`, its S3 fetcher is automatically registered upon initialization.

### Programmatic Usage with DownloadClient

```python
import asyncio
from corekat.config import config
from corekat.client.filedl import DownloadClient
from stashkat.init import init as stashkat_init

async def main():
    # Load config (which should include S3 settings)
    conf = config()
    # Initialize stashkat to register S3 fetcher
    stashkat_init(conf)

    downloader = DownloadClient()

    # Download from S3 using corekat's DownloadClient
    file_info = await downloader.download(
        source="s3://my-bucket/my-file.txt",
        dest_dir="/tmp"
    )
    print(f"Downloaded {file_info.path}")

if __name__ == "__main__":
    asyncio.run(main())
```

### Direct S3Client Usage

```python
import asyncio
from stashkat.config import config
from stashkat.s3 import S3Client
from stashkat.models import StoragePath

async def main():
    conf = config()
    client = S3Client(conf.s3)
    
    # Upload file
    storage_path = await client.upload_file("local/file.txt", dest="uploads/file.txt")
    print(f"Uploaded to: {storage_path.url}")
    
    # Download file
    remote = StoragePath.model_validate("s3://my-bucket/uploads/file.txt")
    await client.download_file(remote, dest="/tmp/downloaded.txt")
    
    # List files
    files = await client.list(prefix="uploads/")
    for file in files:
        print(f"Found: {file.url}")

if __name__ == "__main__":
    asyncio.run(main())
```

## CLI Usage

### Configuration

The CLI requires S3 configuration to be present in a `config.yaml` or `localconfig.yaml` file, or via environment variables (prefixed with `STASHKAT_`).

Example `config.yaml`:
```yaml
s3:
  bucket: "my-default-bucket"
  region: "us-east-1"
  access_key: "..." # Or use environment variables
  secret_key: "..." # Or use environment variables
```

### Commands

**Upload a file:**
```bash
stashkat s3 upload /path/to/local/file.txt
```

**Upload with a specific destination key:**
```bash
stashkat s3 upload /path/to/local/file.txt --dest "archive/file.txt"
```

**Download a file:**
```bash
stashkat s3 download s3://my-bucket/archive/file.txt /path/to/save/location.txt
```

**Copy a file:**
```bash
stashkat s3 copy s3://my-bucket/source.txt s3://my-bucket/destination.txt
```
