Metadata-Version: 2.4
Name: files-sdk-uploadthing
Version: 0.1.0a2
Summary: UploadThing adapter for files-sdk
Project-URL: Homepage, https://github.com/menelsystems/files-sdk-py
Project-URL: Repository, https://github.com/menelsystems/files-sdk-py
Project-URL: Issues, https://github.com/menelsystems/files-sdk-py/issues
Author-email: Carter Himmel <carter@menelsystems.com>
License-Expression: MIT
License-File: LICENSE
Keywords: files,object-storage,storage,uploadthing
Classifier: Development Status :: 3 - Alpha
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: files-sdk
Requires-Dist: httpx>=0.27
Requires-Dist: sqids>=0.5.2
Description-Content-Type: text/markdown

# files-sdk-uploadthing

[UploadThing](https://uploadthing.com) adapter for [files-sdk](../files-sdk).
Sync and async variants over `httpx`, with locally-computed HMAC presigned
URLs (ported from the upstream TypeScript SDK — no UT-side roundtrip for
upload URL generation).

## Install

```bash
uv add files-sdk files-sdk-uploadthing
```

## Usage

```python
from files_sdk import Files
from files_sdk_uploadthing import UploadThingAdapter

files = Files(adapter=UploadThingAdapter())   # reads UPLOADTHING_TOKEN
files.upload("users/123/avatar.png", b"...")
print(files.download("users/123/avatar.png").as_bytes())
```

Async:

```python
from files_sdk_uploadthing import AsyncUploadThingAdapter

a = AsyncUploadThingAdapter()
await a.upload("users/123/avatar.png", b"...")
```

## Auth

Set `UPLOADTHING_TOKEN` (the base64 JSON token from your UploadThing
dashboard's API Keys page) in the environment, or pass `token=` explicitly.
The decoded `apiKey` is the only secret sent — the token's `appId` and
`regions` are extracted client-side.

## Notes on the protocol mapping

The adapter's `key: str` maps to UploadThing's `customId`, so paths like
`users/123/avatar.png` round-trip cleanly. The opaque per-file `fileKey` is
generated client-side and never surfaced. A few protocol mismatches are
handled transparently:

- **No prefix filter on `listFiles`** — fetched pages are filtered in Python.
  The `cursor` is a stringified offset. Large accounts will see this.
- **No server-side `copy`** — implemented as download + reupload.
- **No HEAD endpoint** — `head()` uses a one-byte ranged GET; the
  `Content-Range` header carries the true size.
- **CDN routing by `customId` doesn't resolve unicode keys** — falls back
  to `/v6/getFileUrl` (one extra API roundtrip) when the direct fetch 404s.

## Development

Live conformance tests require `UPLOADTHING_TOKEN`:

```bash
export UPLOADTHING_TOKEN=eyJh...
uv run pytest packages/files-sdk-uploadthing/
```

Without the token, only the offline tests (`_token`, `_signing`, `_hash`)
run; the conformance suite skips.
