Metadata-Version: 2.4
Name: bq-nats-client
Version: 0.1.3
Summary: Python gRPC client for NATS Go sidecar
Author-email: Marcus Lee <marcuslee@balaenaquant.com>
License: MIT
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Networking
Requires-Python: >=3.11
Requires-Dist: grpcio>=1.60.0
Requires-Dist: protobuf>=5.0.0
Provides-Extra: dev
Requires-Dist: build; extra == 'dev'
Requires-Dist: grpcio-tools>=1.60.0; extra == 'dev'
Requires-Dist: hatch; extra == 'dev'
Requires-Dist: twine; extra == 'dev'
Description-Content-Type: text/markdown

# bq-nats-client

Python gRPC client for the NATS Go daemon. Exposes publish, subscribe, and JetStream operations via a thin async API that mirrors `nats.py`.

## Architecture

```
Python app  ──gRPC (Bearer JWT)──►  Go daemon  ──NATS──►  NATS server
```

The Go daemon runs as its **own deployment** and owns the NATS connection. This
library only connects to it over gRPC — it does **not** start or bundle the daemon.
On the first call the client authenticates with its api-key, gets a short-lived
JWT, and attaches it to every request automatically.

## Install

```bash
pip install bq-nats-client
```

## Configuration

The client reads these env vars (explicit constructor args take precedence):

| Env | Meaning | Default |
|-----|---------|---------|
| `BQ_NATS_GRPC_ADDR` | address of the running daemon | `localhost:50052` |
| `BQ_NATS_API_KEY` | api-key the daemon verifies (→ JWT) | — |
| `BQ_NATS_TLS_CA` | CA cert to verify the daemon's TLS cert | — (plaintext) |

## Usage

```python
import asyncio
from nats_client import NATSClient, Msg

async def main():
    # grpc_addr + api_key come from env, or pass explicitly:
    nc = NATSClient(grpc_addr="localhost:50052", api_key="<prime-api-key>")

    # plain publish
    await nc.publish("orders.new", b'{"id": 1}')

    # JetStream
    await nc.jetstream()
    ack = await nc.js_publish("orders.new", b'{"id": 2}')
    print(f"ack: stream={ack.stream} seq={ack.seq}")

    # subscribe
    async def on_msg(msg: Msg):
        print(f"[{msg.subject}] {msg.data}")

    await nc.subscribe("orders.>", cb=on_msg)
    await asyncio.sleep(10)
    await nc.close()

asyncio.run(main())
```

## API

### `NATSClient(grpc_addr=None, api_key=None, tls_ca=None)`

| Method | Description |
|--------|-------------|
| `publish(subject, payload, reply, headers)` | Core NATS publish |
| `jetstream(prefix, domain, timeout)` | Configure JetStream context (call once) |
| `js_publish(subject, payload, ...)` → `PubAck` | JetStream publish |
| `subscribe(subject, cb, queue, ...)` → `Task` | Subscribe; cb fires per message |
| `close()` | Cancel subscribers and close gRPC channel |

## Requirements

- Go daemon running as a separate process/deployment (`just run`, or a compiled `go/dist` binary)
- NATS server reachable from the daemon
- A valid api-key for the daemon to verify
