Metadata-Version: 2.4
Name: f69
Version: 0.1.7
Summary: Python client for the f69-edge HTTP API
License-Expression: MIT
Requires-Python: >=3.12
Requires-Dist: httpx>=0.27
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == 'dev'
Description-Content-Type: text/markdown

# f69-edge (Python SDK)

Small **httpx-based** client for the f69-edge HTTP API.

Requires **Python 3.12+**.

## Install

```bash
pip install f69
```


## Usage

```python
import os

from f69 import F69EdgeClient, F69EdgeError

client = F69EdgeClient(
    base_url=os.environ.get("F69_EDGE_URL", "http://127.0.0.1:8081"),
    # From control plane: POST .../projects/<project>/service-accounts - use bearer_token or `<id>.<secret_key>`.
    # Tokens are reader (evaluate only) or writer (identify + evaluate); each token is bound to one project + environment.
    api_key=os.environ["F69_SERVICE_ACCOUNT_BEARER"],
)

client.health()  # GET /health (no auth)

client.identify(
    type="user",
    external_id="user_42",
    attributes={"plan": "pro", "region": "eu"},
)

flags = client.evaluate(id="user_42", type="user")
# flags → [
#   {"key": "new_checkout", "value": True, "reason": "TARGETING_MATCH", "version": "live"},
#   ...
# ]

client.close()
```

### Evaluate semantics

`POST /v1/evaluate` takes `{"id", "type"}` and optional `"keys"`. Omit `keys`
to evaluate every feature in the token's project; pass a non-empty `keys` list
to evaluate only those feature keys. The server looks up the entity in the
token's project + environment (it must have been identified first via
`/v1/identify`) and replies with a list of results. Each entry carries `key`,
`value`, `reason` (one of `TARGETING_MATCH`, `SPLIT`, `DEFAULT`, `FALLBACK`,
`ERROR`), and a manifest `version` string scoped to that project/environment.

### Project scope

Service-account tokens now scope to a **project + environment**, not to a whole
workspace. Create a project in control first, then mint tokens under it. After
upgrading from a pre-project release, the server invalidates old tokens and
returns `HTTP 401 token_reissue_required` until a new token is issued from the
dashboard.

Use as a context manager to close the underlying HTTP client:

```python
with F69EdgeClient(base_url="http://127.0.0.1:8081", api_key="...") as client:
    client.health()
```

Errors on non-2xx responses raise **`F69EdgeError`** with `status`, `url`, and parsed `body` when available.

## API surface

| Method | HTTP | Auth |
|--------|------|------|
| `health()` | `GET /health` | No |
| `identify(*, type, external_id, attributes=None, label=UNSET)` | `POST /v1/identify` | `Authorization: Bearer <serviceAccountId>.<secretKey>` |
| `evaluate(*, id, type, keys=None)` | `POST /v1/evaluate` | Same |
