Metadata-Version: 2.4
Name: ngrok-fastapi
Version: 0.1.0
Summary: Bring ngrok Traffic Policy, pooling, and binding config to FastAPI, via its own lifespan hook.
License-Expression: MIT OR Apache-2.0
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE-APACHE
License-File: LICENSE-MIT
Requires-Dist: ngrok>=1.4.0
Requires-Dist: fastapi>=0.100.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.24.0; extra == "dev"
Requires-Dist: uvicorn>=0.29.0; extra == "dev"
Requires-Dist: httpx>=0.27.0; extra == "dev"
Dynamic: license-file

# ngrok-fastapi

Bring ngrok Traffic Policy, pooling, and binding config to FastAPI — via FastAPI's own
lifespan hook, with one call:

```python
from fastapi import FastAPI
import ngrok_fastapi

app = FastAPI()
ngrok_fastapi.attach(app, ngrok_fastapi.Config(port=8000))
```

## What it is

A small FastAPI-native ngrok library. `attach()`/`attach_many()` wrap an app's existing
lifespan context manager so an ngrok tunnel opens when the app starts and closes when it stops. 

## Setup

1. Sign up at [ngrok.com](https://ngrok.com) and grab an authtoken from
   [the dashboard](https://dashboard.ngrok.com/authtokens).
2. Set it as an env var: `NGROK_AUTHTOKEN=your_token_here`
3. `pip install ngrok-fastapi` and call `attach()` — see [`examples/basic.py`](examples/basic.py).

## Config

```python
ngrok_fastapi.attach(app, ngrok_fastapi.Config(
    port=8000,
    url="your-reserved-domain.ngrok.app",  # None = account's default dev domain
    pooling=False,
    traffic_policy="""
on_http_request:
  - actions:
      - type: basic-auth
        config:
          credentials:
            - "user:password123"
""",
    binding=None,  # ngrok_fastapi.Binding.INTERNAL, etc.
))
```

See [`examples/with_config.py`](examples/with_config.py) for a working example.

| Field | Type | Description |
|---|---|---|
| `port` | `int` | Local port this endpoint forwards to. |
| `url` | `Optional[str]` | Reserved domain for this endpoint. `None` falls back to the account's default dev domain. |
| `pooling` | `bool` | Opt in to ngrok endpoint pooling — required if another endpoint on the same session would otherwise collide on the same domain. See [Collisions](#collisions). |
| `traffic_policy` | `Optional[str]` | A raw [ngrok Traffic Policy](https://ngrok.com/docs/traffic-policy/) document (YAML or JSON) — the mechanism for auth, IP restrictions, header manipulation, webhook verification, and more. |
| `binding` | `Optional[Binding]` | `PUBLIC` / `INTERNAL` / `KUBERNETES` ingress configuration. Not part of Traffic Policy (checked ngrok's actions reference directly — no equivalent exists), so it stays a standalone field. `INTERNAL` requires `url` to end in `.internal`, enforced by ngrok itself (`ERR_NGROK_9029` if it doesn't). |

## Multiple endpoints

`attach_many(app, configs)` opens one endpoint per `Config`, all on a single session, and
ties all of them to the same app's lifespan. `attach(app, config)` is just
`attach_many(app, [config])`.

```python
ngrok_fastapi.attach_many(app, [
    ngrok_fastapi.Config(port=8000, url="app.mycompany.ngrok.app"),
    ngrok_fastapi.Config(port=8001, url="api.mycompany.ngrok.app"),
])
```

## Development

```
python3 -m venv venv && source venv/bin/activate
pip install -e ".[dev]"
pytest
python examples/basic.py
```

See [`DESIGN.md`](DESIGN.md) for the design rationale and everything confirmed empirically
along the way.

## License

MIT OR Apache-2.0
