Metadata-Version: 2.5
Name: usewind
Version: 0.1.1
Summary: Server SDK for Connect with Wind — OAuth connect routes, atomic refresh-token rotation, and billed inference calls.
Project-URL: Homepage, https://docs.usewind.app/connect-button-and-sdk
Project-URL: Repository, https://github.com/edwin-ma26/usewind
Author: Wind
License: MIT
Requires-Python: >=3.9
Requires-Dist: httpx>=0.27
Requires-Dist: pydantic>=2
Provides-Extra: fastapi
Requires-Dist: fastapi>=0.100; extra == 'fastapi'
Provides-Extra: test
Requires-Dist: fastapi>=0.100; extra == 'test'
Requires-Dist: pytest-asyncio>=0.23; extra == 'test'
Requires-Dist: pytest>=8; extra == 'test'
Requires-Dist: respx>=0.21; extra == 'test'
Description-Content-Type: text/markdown

# wind (Python SDK)

Publishes as **`usewind`** on PyPI (`import usewind`). Server-only — it handles the `client_secret`
and the rotating `refresh_token`, which must never reach a browser. The
connect button ships separately as `@usewind/browser` (JS; there's no
Python-specific equivalent — browsers only run JavaScript regardless of your
backend language, so every backend pairs with that same package).

Status: **implemented**, mirroring `@usewind/node`'s surface and semantics.
See **[DESIGN.md](./DESIGN.md)** for the full API, module map, and the
handful of deliberate deviations from the original design note (Flask/Django
adapters not built yet, management calls are flat functions instead of a
nested namespace).

Not a port. The retired `ai-wallet/sdks/wind-python` targeted the previous
product (`sk_live_` keys, `windUserId` in the body, `/v1/ai/:featureId`).

## Shape

```python
import asyncio
from usewind import wind
from usewind.types import ChatParams, ChatMessage

# 0. one persistence contract — get/set/delete keyed by your user id. set() is
#    called on first connect AND every refresh-token rotation, and is awaited
#    before the new tokens are used. Back it with your database.
wind.configure(
    grant_store={
        "get": lambda user_id: db.get_wind_grant(user_id),
        "set": lambda user_id, grant: db.set_wind_grant(user_id, grant),
        "delete": lambda user_id: db.clear_wind_grant(user_id),
    },
)

# 1. the connect routes (FastAPI; Flask/Django adapters are a planned gap — see DESIGN.md)
app.include_router(wind.fastapi_router(
    current_user=lambda request: request.session.get("user_id"),
    on_connected=lambda user_id, grant: analytics.track(user_id, "wind_connected"),  # optional hook, not persistence
))

# 2. a billed call — refresh-and-retry, idempotency key, feature header handled inside.
#    Every I/O method is native async (a-prefixed); the non-prefixed sibling
#    is a thin asyncio.run() wrapper for plain scripts, not callable from
#    inside an already-running event loop (e.g. a FastAPI endpoint — use the
#    async method there instead).
async def handle_chat(user_id: str, messages):
    res = await wind.connection(user_id).model("gpt-4o").achat(
        ChatParams(messages=[ChatMessage(role="user", content=m) for m in messages], max_tokens=500)
    )
    return res.wind.user_charge_mc, res.wind.allocation_remaining_mc

# or, to bill against a registered feature's server-resolved default_model:
res2 = wind.connection(user_id).feature("chat").chat(ChatParams(messages=messages))  # sync

# 3. webhooks
event = wind.verify(payload=raw_body, signature=request.headers["wind-signature"])
```

Credentials come from `Wind(...)`/`wind.configure(...)` or the env vars
`WIND_CLIENT_ID`, `WIND_CLIENT_SECRET`, `WIND_REDIRECT_URI`. `grant_store` is
required for `wind.fastapi_router()` / `wind.connection()`; without it those
raise `WindConfigError`. Use `create_wind(...)` for an explicit instance
(tests, multi-tenant), or `memory_grant_store()` from this package for a
dev-only in-memory `grant_store`.

## Install

```
pip install usewind            # core
pip install usewind[fastapi]   # + the FastAPI connect-route adapter
```

## Development

```
cd sdks/wind-python
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[test]"
pytest
```

Contract source of truth: `apps/docs/public/openapi.yaml`. The raw HTTP flow
the SDK wraps: `apps/docs/public/skills/wind-connect/SKILL.md`.
