Metadata-Version: 2.4
Name: vwp-sdk
Version: 0.5.0a1
Summary: VWP Python SDK — primitives for vibe-coded backends (rate limiting, auth, notifications, and more).
Project-URL: Homepage, https://vibewithprimitiveai.com
Project-URL: Documentation, https://vibewithprimitiveai.com/docs
Project-URL: Source, https://github.com/BackpackNecoG/vwp
Author-email: Primitive AI <rennecog@gmail.com>
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: auth,primitives,rate-limit,rate-limiting,vibecoding,vwp
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.9
Requires-Dist: httpx>=0.27
Requires-Dist: typing-extensions>=4.0; python_version < '3.11'
Provides-Extra: dev
Requires-Dist: anyio>=4.0; extra == 'dev'
Requires-Dist: build>=1.2; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
Requires-Dist: pytest-httpx>=0.32; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.7; extra == 'dev'
Requires-Dist: twine>=5.0; extra == 'dev'
Description-Content-Type: text/markdown

# vwp-sdk

Python SDK for [VWP](https://vibewithprimitiveai.com) — primitives for vibe-coded backends.

```bash
pip install vwp-sdk
```

## Quickstart

```python
import vwp

client = vwp.Client(api_key="vwp_test_...")  # or set VWP_API_KEY in env

result = client.rate_limit.check(
    key="login:user@example.com",
    limit=5,
    window="15m",
)
if not result.allowed:
    # Block this request — your handler returns 429 to the end user.
    print(f"Try again in {result.retry_after_seconds}s")
```

Or, async:

```python
import asyncio
import vwp

async def main():
    async with vwp.AsyncClient(api_key="vwp_test_...") as client:
        result = await client.rate_limit.check(
            key="login:user@example.com", limit=5, window="15m",
        )
        print(result)

asyncio.run(main())
```

## What's in this release (0.2.0a1)

- **`vwp.rate_limit.check(...)`** — `SECURITY-RATE-LIMIT-001`, fully wired against
  `https://api.vibewithprimitiveai.com/v1`.
- **`vwp.auth.magic_link.request(email, return_to, ...)`** — issues a single-use magic link via
  email (Azure Communication Services on our side).
- **`vwp.auth.magic_link.exchange(request | url | dict, handle?)`** — turns a clicked link into a
  signed JWT session. SDK pulls `_vwp_h` out of the request URL automatically.
- **`vwp.Client` / `vwp.AsyncClient`** — explicit clients for connection reuse.
- **Typed errors** — `ApiKeyError` (401), `BadRequestError` (400), `MetaRateLimitedError` (429),
  `ServerError` (5xx), `NetworkError` (no response).

Other modules (`vwp.notify`, `vwp.data`, `vwp.queue`) are present as stubs and will be implemented
in subsequent releases. Calling them raises `NotImplementedError` with a pointer to the docs.

### Magic-link quickstart

```python
import vwp

client = vwp.Client(api_key="vwp_test_...")

# Step 1 — user types their email
r = client.auth.magic_link.request(
    email="user@example.com",
    return_to="https://yourapp.com/dashboard",
)
# r.expires_at — when the link expires (default 15 min)
# r.delivery_status — "queued"

# Step 2 — user clicks the link, your callback handler runs:
session = client.auth.magic_link.exchange(request)  # request from your framework
# Or pass the URL/handle directly:
session = client.auth.magic_link.exchange(handle="<_vwp_h value from URL>")

# session.session.user_id, session.session.email — for your user table upsert
# session.jwt — set as a HttpOnly cookie
```

## Errors

Every error subclasses `vwp.VWPError`. Catch the base class to handle anything:

```python
try:
    result = vwp.rate_limit.check(key="...", limit=5, window="15m")
except vwp.ApiKeyError as e:
    print("Bad API key:", e.request_id)
except vwp.BadRequestError as e:
    print("Bad input:", e.field, e.message)
except vwp.VWPError as e:
    print("Other VWP error:", e)
```

## Compatibility

Python 3.9+. Production-tested on 3.12.

## License

Apache-2.0.
