Metadata-Version: 2.5
Name: neocrew-connector
Version: 0.2.1
Summary: Python SDK for Crewlink: connect accounts, call provider APIs, and manage secrets with sync and async clients.
Project-URL: Homepage, https://github.com/WowLabz/crewlink
Project-URL: Source, https://github.com/WowLabz/crewlink/tree/main/packages/connector-py
Author: Neocrew AI
License-Expression: MIT
License-File: LICENSE
Keywords: api,connectors,crewlink,integrations,neocrew,oauth,sdk
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Typing :: Typed
Requires-Python: >=3.9
Requires-Dist: anyio>=3.0
Requires-Dist: httpx>=0.21.2
Requires-Dist: pydantic>=2.0
Requires-Dist: typing-extensions>=4.0.0
Description-Content-Type: text/markdown

# neocrew-connector

Python SDK for the Crewlink integration API. Connect user accounts, call provider
APIs, manage secrets, and issue principal tokens from your backend. Includes
typed synchronous and asynchronous clients.

## Install

Requires Python 3.9 or newer.

```sh
pip install neocrew-connector
```

## Quick start

Set `CREWLINK_API_KEY` and `CREWLINK_BASE_URL` in your server environment.
Use your Crewlink API URL and a key with `connections:read`.

```python
import os
from neocrew_connector import Crewlink

client = Crewlink(
    token=os.environ["CREWLINK_API_KEY"],
    base_url=os.environ["CREWLINK_BASE_URL"],
    max_retries=0,
    timeout=30.0,
)
page = client.connections.list(limit=20)
for connection in page.data:
    print(connection.id, connection.status)
```

The constructor also reads these environment variables if the arguments are
omitted. Set the URL for production; its fallback is `http://localhost:4310`.
`max_retries=0` disables automatic SDK retries; see Errors below.

## Connect and call a provider

The integration must already be enabled. Use its unique key (`github` here),
not its display name. A **principal** is your user, service, or agent; obtain its
ID from your authenticated server session.

```python
session = client.connect.create_session(
    principal_id="user_123",
    allowed_integrations=["github"],
)
connect_url = session.data.connect_url
```

Send `connect_url` only to that principal and open it to authorize their account.
Session creation requires `connections:write`. Once authorization completes:

```python
github = client.proxy.for_(integration_key="github", principal_id="user_123")
response = github.get("/user")
response.raise_for_status()
profile = response.json()
```

Use `connection_id` instead of `principal_id` if you have a connection ID, never
both. Proxy methods include `get`, `post`, `put`, `patch`, and `delete` and return
`httpx.Response`. Reads need `connections:read`; writes need `connections:write`.

## Async

```python
import asyncio
import os
from neocrew_connector import AsyncCrewlink

async def main():
    async_client = AsyncCrewlink(
        token=os.environ["CREWLINK_API_KEY"],
        base_url=os.environ["CREWLINK_BASE_URL"],
        max_retries=0,
    )
    page = await async_client.connections.list(limit=20)
    return page.data

connections = asyncio.run(main())
```

In an existing event loop, use `await main()` instead. Async proxy methods use
an `a` prefix, for example `await github.aget("/user")` on a proxy created from
`async_client.proxy.for_(...)`.

## Principal tokens

Mint a token that acts as one principal, for an agent or a browser. It is shown once.

```python
issued = client.principal_tokens.create(
    principal_id="user_123",
    name="support-agent",
    integrations=["github"],
    scope="read",
    expires_at="2026-12-31T00:00:00Z",
)
token = issued.data.token  # an MCP client sends this as Authorization: Bearer
```

Needs `principals:write`. Keep the integration list, scope and expiry as narrow as the job allows.

## Secrets

Store a provider's values for one principal, then read them back as environment variables.

```python
client.secrets.create(
    principal_id="user_123",
    provider="openai",
    label="prod",
    values={"api_key": "sk-proj-..."},
)
bundles = client.secrets.read_env(principal_id="user_123", labels=["prod"]).data.bundles
for bundle in bundles:
    print(bundle.env)  # {"OPENAI_API_KEY": "sk-proj-..."}
```

`create` needs `secrets:write`; `read_env` needs `secrets:read`.

Keep API keys on the server. Never log tokens or decrypted secrets.

## Errors

API calls raise `neocrew_connector.core.ApiError` with `status_code` and `body`:

```python
from neocrew_connector.core import ApiError

try:
    client.connections.get(id="conn_123")
except ApiError as error:
    print(error.status_code, error.body)
```

Proxy calls return the response even on an HTTP error, so check it yourself with `response.raise_for_status()`.

API calls retry twice by default on network errors, 408, 409, 429 and 5xx, including writes. Pass `max_retries=0` if a retry could duplicate work.

## Pagination

```python
cursor = None
while True:
    page = client.connections.list(limit=50, cursor=cursor)
    for connection in page.data:
        print(connection.id)
    cursor = page.next_cursor
    if cursor is None:
        break
```

## License

MIT. The license text is included in the package.
