Metadata-Version: 2.4
Name: threads-sdk
Version: 0.3.0
Summary: Async Python gRPC client for the Go Threads (Barcelona) private API SDK
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: grpcio<2,>=1.82.1
Requires-Dist: protobuf<8,>=7.35.0

# threads-sdk

`threads-sdk` 是 `go-threads-api` 的 Python 异步客户端。SDK 只负责连接 Go gRPC server、构造功能请求和返回
结果，不实现业务编排、持久化或任务队列。

## 安装

从对应 Go server 版本的公开文档下载页获取 wheel：

- 生产版本：<https://threads-api.es007.com/latest/docs/sdk-download/>
- 测试版本：<https://threads-api.es007.com/test/latest/docs/sdk-download/>

```bash
uv add ./threads_sdk-X.Y.Z-py3-none-any.whl
```

也可以下载 `threads_sdk-X.Y.Z-copy.zip`，解压后把完整的 `threads_sdk/` 目录复制到自己的项目中。
运行环境只需要安装发行元数据声明的 `grpcio` 和 `protobuf`，不需要 `grpcio-tools`、仓库源码或单独
生成 stub。SDK 版本与同 Tag 的 Go server 镜像版本完全一致；测试 Tag 对应 prerelease，生产 Tag 对应
正式 Release。

仓库本地路径安装：

```bash
uv add ./python
```

仓库开发环境使用：

```bash
uv sync --project python
uv run --project python python -m pytest -q \
  python/tests/test_distribution.py \
  python/tests/test_facade.py \
  python/tests/test_account_state_go_blackbox.py \
  python/tests/test_api_inventory.py \
  python/tests/test_e2e_sdk_contract.py \
  python/tests/test_rpc_recording.py
```

上述命令是无凭据离线门禁。真实 Threads API 验收需要按仓库根目录 README 配置受保护身份和写入授权。

## 最小调用

```python
from threads_sdk import (
    LoginAssurance,
    Proxy,
    ProxyProtocol,
    ThreadsClient,
    dump_account_state,
    load_account_state,
)


async with ThreadsClient("127.0.0.1:50051") as client:
    # 登录任务：Go server 生成设备；强类型 Proxy 可省略。
    # 代理账号密码可同时省略，用于 IP 白名单出口。
    result = await client.auth.login(
        username="account",
        password="secret",
        two_factor_seed="BASE32_TOTP_SEED",
        proxy=Proxy(
            host="proxy.example",
            port=1080,
            protocol=ProxyProtocol.SOCKS5H,
            username="proxy-user",
            password="proxy-password",
        ),
    )
    if not result.success:
        raise RuntimeError(result.stability_warning)
    if result.assurance != LoginAssurance.EXTERNAL_SIGNER_SUCCEEDED:
        raise RuntimeError("登录没有取得外部 keybox signer 证明")
    save_to_your_storage(dump_account_state(result.account_state))

    # 后续独立发帖任务：恢复完整状态，不再传账号、密码、2FA、代理或设备。
    state = load_account_state(load_from_your_storage())
    account = client.account(state)
    media = await account.posts.create_text_post("hello")
    save_to_your_storage(dump_account_state(account.state))
```

`AccountClient` 只在当前进程内保存本次调用后的最新状态。ARQ 多进程、任务分配、数据库格式、锁和重试策略
均由使用者决定；SDK 不读写任何状态存储。同一个 `AccountClient` 内的 RPC 会串行完成状态往返，避免并发
响应互相覆盖；不同账号应创建不同 `AccountClient`，可以完全并发执行。

`dump_account_state()` 返回的是未加密二进制，包含 Session token、完整设备身份和可能存在的代理凭据。
SDK 不提供密钥管理；生产使用者必须在自己的数据库或密钥系统中加密保存，并限制日志和备份访问。
公开 `AccountState`、`LoginSession` 和 `LoginResult` 不直接暴露生成 protobuf，其 `repr()` / `str()`
不会输出 token、claim、设备标识或代理账号密码。序列化必须使用 `dump_account_state()`，不要访问
`threads_sdk._generated` 或依赖私有 `_to_proto()`。

每个 RPC 默认使用 60 秒 deadline。可在连接级设置 `ThreadsClient(default_timeout=30)`，也可在单次调用
覆盖，例如 `await account.posts.create_text_post("hello", timeout=10)`。`default_timeout=None` 表示不
设置 SDK 默认 deadline；ARQ 的任务超时、取消、重试和幂等仍由使用者管理。

`Proxy` 是唯一公开代理类型，支持 `HTTP`、`HTTPS`、`SOCKS5`、`SOCKS5H`。`username` 与 `password`
必须同时提供或同时省略。环境变量或配置文件中的字符串先用 `Proxy.from_url()` 显式转换；
`host:port:username:password` 四段式固定解释为 SOCKS5。登录成功后代理随 `AccountState` 保存，
`ThreadsClient` 不接受账号代理。

跨主机连接时启用 TLS：

```python
from pathlib import Path

from threads_sdk import ThreadsClient


async with ThreadsClient(
    "threads-server.example.com:50051",
    tls=True,
    root_certificates=Path("grpc-ca.pem").read_bytes(),
    api_key="replace-with-at-least-32-characters",
    default_timeout=30,
) as client:
    ...
```

使用公开 CA 时可以省略 `root_certificates`。非 loopback server 必须设置至少 32 字符的
`THREADS_GRPC_API_KEY`，SDK 通过 `api_key` 自动发送 `x-threads-api-key`。
