Hookah is a Radix DLT event monitoring and webhook delivery platform. It lets developers authenticate with Radix ROLA, register event triggers, and receive webhook deliveries when matching on-ledger events appear in the transaction stream.
This is a TypeScript monorepo managed with pnpm and Turborepo.
| Path | Purpose |
|---|---|
apps/dashboard |
Next.js app for authentication, trigger management, webhooks, and JSON-RPC/tRPC endpoints |
apps/streamer |
Long-running worker that follows Radix transactions and dispatches matching webhook deliveries |
apps/webhook-test-server |
Local helper for testing webhook delivery |
packages/api |
Effect-based application services, tRPC routers, auth, trigger matching, webhook execution, and transaction-stream handling |
packages/db |
Drizzle schema and migrations |
packages/domain |
Shared domain schemas and auth payload types |
packages/radix |
Local Radix utility scripts built on radix-web3.js |
packages/sdk |
Public TypeScript SDK for Hookah clients |
packages/sbor-ez-mode |
SBOR helper package used by Radix event tooling |
www |
Docusaurus documentation site |
e2e |
End-to-end utilities and tests |
Hookah has two primary runtime processes:
- Dashboard: serves the web app, auth routes, tRPC, and JSON-RPC endpoints. It also runs database migrations during deployment startup.
- Streamer: reads Radix transaction pages, transforms events, finds matching triggers, executes webhooks directly, writes execution logs, and advances stream checkpoints only after processing succeeds.
Shared infrastructure:
- PostgreSQL stores users, sessions, webhooks, triggers, logs, and stream checkpoints.
- Redis stores the trigger registry used by the transaction stream handler.
- Radix Gateway and
radix-web3.jsprovide network reads, ROLA support, and local script transaction helpers.
flowchart LR
browser["Dashboard browser"]
sdk["External app using hookah-sdk"]
jsonrpc["JSON-RPC client"]
dashboard["Next.js dashboard app"]
api["tRPC and JSON-RPC routes"]
effects["Effect application services"]
db[(PostgreSQL)]
redis[(Redis trigger registry)]
streamer["Streamer worker"]
gateway["Radix Gateway"]
webhook["External webhook endpoints"]
browser --> dashboard
dashboard --> api
sdk --> api
jsonrpc --> api
api --> effects
effects --> db
effects --> redis
effects --> gateway
streamer -->|read transaction pages| gateway
streamer -->|load webhooks and write logs| db
streamer -->|load active triggers| redis
streamer -->|POST event payloads| webhook
streamer -->|advance checkpoints| db
sequenceDiagram
actor User
participant Dashboard
participant Wallet as Radix wallet
participant API as Auth route
participant Auth as AuthService
participant Rola as RolaService
participant DB as PostgreSQL
User->>Dashboard: Open login
Dashboard->>API: auth.generateChallenge
API->>Auth: createChallenge
Auth->>DB: Store challenge
API-->>Dashboard: Challenge
Dashboard->>Wallet: Request ROLA proof
Wallet-->>Dashboard: Signed persona proof
Dashboard->>API: auth.signInWithRola
API->>Auth: Verify challenge and proof
Auth->>DB: Read and consume challenge
Auth->>Rola: Verify signed challenge
Auth->>DB: Upsert user and create session
API-->>Dashboard: Set session cookie
sequenceDiagram
actor User
participant Dashboard
participant Action as Server action
participant API as Webhook router
participant Service as CreateWebhookService
participant DB as PostgreSQL
User->>Dashboard: Submit webhook form
Dashboard->>Action: createWebhook form action
Action->>Action: Validate form fields
Action->>API: webhook.create
API->>Service: createWebhookProgram
Service->>Service: Normalize URL and headers
Service->>DB: Insert webhook definition
DB-->>Service: Stored webhook
Service-->>API: Public webhook
API-->>Action: Success
Action-->>Dashboard: Revalidate dashboard data
sequenceDiagram
participant Gateway as Radix Gateway
participant Streamer
participant Redis as Redis trigger registry
participant Matcher as TriggerMatcherService
participant DB as PostgreSQL
participant Executor as WebhookExecuterService
participant Webhook as External webhook
Streamer->>Gateway: Read transactions from checkpoint
Gateway-->>Streamer: Transaction page
Streamer->>Streamer: Transform transaction events
Streamer->>Redis: Load candidate triggers by event rules
Redis-->>Streamer: Active triggers
Streamer->>Matcher: Match events and conditions
Matcher-->>Streamer: Event matches
Streamer->>DB: Load webhook definitions
Streamer->>Executor: Execute matching webhooks
Executor->>Webhook: POST event payload
Webhook-->>Executor: Delivery response
Streamer->>DB: Write execution logs
Streamer->>DB: Advance stream checkpoint after processing
sequenceDiagram
participant App as SDK consumer app
participant SDK as hookah-sdk
participant Rola as SDK ROLA service
participant API as Hookah tRPC API
participant DB as PostgreSQL
App->>SDK: createHookahSdk with public key and signer
App->>SDK: auth
SDK->>API: auth.generateChallenge
API->>DB: Store challenge
API-->>SDK: Challenge
SDK->>Rola: Build persona and sign challenge
Rola-->>SDK: Signed ROLA proof
SDK->>API: auth.signInWithRola
API->>DB: Upsert user and create session
API-->>SDK: Auth success and session cookie
App->>SDK: getTrpcClient
SDK-->>App: Authenticated tRPC client
App->>API: Manage webhooks, triggers, and logs
- Node.js 20.9.0 or newer
- pnpm 11.7.0
- PostgreSQL for local persistence
- Redis for trigger registry and runtime cache
Install dependencies:
pnpm installCreate a local environment file:
cp .env.example .envFill in the local values you need. Keep real credentials out of committed files. pnpm dev loads .env before starting the local processes. For one-off commands outside the root dev script, load the file into your shell first:
set -a
source .env
set +aStart local infrastructure:
docker compose up -d postgres redis
pnpm db:migrateRun the dashboard and streamer dev servers:
pnpm devThe dashboard runs at http://localhost:3000. The streamer runs in the same terminal through Turborepo and processes live Radix transaction streams.
Run individual processes when needed:
pnpm dev:dashboard
pnpm dev:streamerRun the docs site at http://localhost:3003:
pnpm dev:docsUseful local commands:
pnpm dev
pnpm dev:dashboard
pnpm dev:streamer
pnpm dev:docs
pnpm run check-types
pnpm run test
pnpm run build
pnpm run ciDatabase commands:
pnpm db:generate
pnpm db:migrate
pnpm db:studioRadix utility commands:
pnpm radix:setup
pnpm radix:get-xrd
pnpm radix:send-early
pnpm radix:generate-mnemonicStart from .env.example. The core runtime variables are:
| Variable | Purpose |
|---|---|
DATABASE_URL |
PostgreSQL connection string used by dashboard, streamer, and db scripts |
REDIS_URL |
Redis connection string used by trigger registry and streamer runtime |
HOOKAH_URL |
Public dashboard/API base URL used by server-side services and SDK config |
NEXT_PUBLIC_APP_URL |
Browser-facing dashboard origin |
EXPECTED_ORIGIN |
Optional explicit origin for auth and CORS checks |
RADIX_NETWORK_ID |
1 for Mainnet, 2 for Stokenet |
DAPP_DEFINITION_ADDRESS |
Server-side Radix dApp definition address for the selected network |
NEXT_PUBLIC_RADIX_NETWORK_ID |
Browser-side Radix network id for Radix Connect |
NEXT_PUBLIC_DAPP_DEFINITION_ADDRESS |
Browser-side dApp definition address for Radix Connect |
AUTH_SECRET |
Session/authentication secret; required in production |
REINDEX_TRIGGERS_ON_STARTUP |
Set to true to rebuild the Redis trigger index when streamer starts |
Docker deployment helpers also read DATABASE_URL_DEV, REDIS_URL_DEV, DATABASE_URL_PROD, and REDIS_URL_PROD. E2E and Radix utility variables are documented in .env.example next to the commands that need them.
Production secrets should live in your deployment secret store, not in this repository.
The main gate is:
pnpm run ciIt runs formatting checks, linting, type checks, non-e2e tests, and builds. E2E tests are kept separate because they require configured external services and Radix test accounts.
Local E2E runs load .envrc and .env before starting tests:
pnpm e2e:localFor a full local E2E run, configure Radix test keys and a public webhook receiver. SDK webhook delivery tests require NGROK_AUTH_TOKEN so the test webhook server can be exposed through ngrok, or SDK_TEST_WEBHOOK_URL pointing at another public HTTPS receiver. Without one of those values, the SDK webhook delivery tests are skipped because localhost webhook URLs are rejected by the API safety checks.
GitHub Actions runs the same gate on pushes and pull requests, plus pnpm audit --audit-level moderate.
See SECURITY.md. Do not commit real private keys, session secrets, database credentials, Redis passwords, npm tokens, or webhook credentials. Use .env.example for names and blank placeholders only.
See CONTRIBUTING.md.
MIT. See LICENSE.