Metadata-Version: 2.4
Name: rrweb-relay
Version: 0.1.0
Summary: Framework-agnostic python-socketio relay for live rrweb session mirroring (record -> fan-out -> replay).
Project-URL: Homepage, https://github.com/rrweb-live/rrweb/tree/main/packages/rrweb-relay#readme
Project-URL: Repository, https://github.com/rrweb-live/rrweb
Project-URL: Issues, https://github.com/rrweb-live/rrweb/issues
Author: rrweb-live
License: MIT
License-File: LICENSE
Keywords: asgi,live,relay,rrweb,session-mirroring,session-replay,socketio
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: AsyncIO
Classifier: License :: OSI Approved :: MIT License
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
Classifier: Topic :: System :: Monitoring
Requires-Python: >=3.11
Requires-Dist: pyjwt>=2
Requires-Dist: python-socketio>=5.11
Provides-Extra: introspection
Requires-Dist: httpx>=0.27; extra == 'introspection'
Provides-Extra: standalone
Requires-Dist: python-dotenv>=1.0; extra == 'standalone'
Requires-Dist: uvicorn[standard]>=0.30; extra == 'standalone'
Description-Content-Type: text/markdown

# rrweb-relay

A framework-agnostic [python-socketio](https://python-socketio.readthedocs.io) relay for **live
rrweb session mirroring**. It receives rrweb events from publishers, keeps a per-session in-memory
buffer (with periodic full-snapshot checkpoints), and fans events out to watchers over socket.io
rooms. It never touches a database and imports **no web framework**.

Pairs with the [`@rrweb-live/sdk`](https://www.npmjs.com/package/@rrweb-live/sdk) browser SDK. Runs **standalone** (any backend
stack can run it alongside) or **mounted** into any ASGI app (Django/FastAPI/Starlette).

## Install

```bash
pip install rrweb-relay                 # core (python-socketio + pyjwt)
pip install "rrweb-relay[standalone]"   # + uvicorn + python-dotenv (for `python -m rrweb_relay`)
pip install "rrweb-relay[introspection]"# + httpx (for the HTTP-introspection verifier)
```

## Auth is pluggable

The only thing a host must provide is a `TokenVerifier`: `verify(token) -> Claims | None` (sync or
async). Built-ins:

- `SharedSecretJWTVerifier` — verify an HS256 JWT with a shared secret + configurable `ClaimMap`
  (which claims map to `user_id`/`email`/`role`) and optional `require_token_type`.
- `HTTPIntrospectionVerifier` — POST the token to an endpoint on your backend that returns claims
  (lets Node/Rails/Go/... plug in their own auth).

Roles are policy: `RolePolicy(publish_roles, watch_roles)` decides who may record vs observe
(empty set = any authenticated role). Preset `DJANGO_CUSTOMER_ADMIN` = customers publish, admins watch.

## Mount into an existing ASGI app

```python
from rrweb_relay import Relay, RelayConfig, SharedSecretJWTVerifier, ClaimMap, DJANGO_CUSTOMER_ADMIN

relay = Relay(RelayConfig(
    verifier=SharedSecretJWTVerifier(secret=SECRET, claim_map=ClaimMap(), require_token_type="access"),
    socketio_path="socket.io",
    role_policy=DJANGO_CUSTOMER_ADMIN,
))
application = relay.asgi_app(other_asgi_app=your_django_or_fastapi_asgi_app)
```

## Run standalone

```bash
cp .env.example .env    # set RELAY_JWT_SECRET to your issuer's signing secret
python -m rrweb_relay   # serves socket.io on RELAY_HOST:RELAY_PORT
```

Point the browser SDK's socket at this origin (directly, or via your reverse proxy's `/socket.io`).

## Wire protocol v1

C→S: `tracker:start`, `tracker:events`, `admin:hello`, `admin:watch`, `admin:unwatch`.
S→C: `sessions`, `watch:init`, `live:events`, `live:end`. Handshake auth: `{ token }`.

## Scaling note

State is an in-process dict + socket.io's default in-memory manager → **single worker only**.
Horizontal scaling needs a socket.io `client_manager` (Redis) + a shared registry. Not included.
