npm run build # compile TypeScript across all packages
npm run dev # starts all services with hot-reload (tsx watch)
npm test # runs all vitest suites across packages
npm run typecheck # type-check all packages
npm run lint # lint all packagesServices run in Docker via docker compose:
npm run services:up # build and start (detached)
npm run services:logs # stream logs
npm run services:down # stop and removeOr run without Docker using tsx:
npm run private-pay -- balance # runs CLI without linkingnpm testRuns all vitest suites across packages (gateway, facilitator, cli, shared) via Turborepo.
The E2E script (scripts/e2e-test.ts) spins up in-memory facilitator and gateway servers on random ports, then exercises the full private token flow:
- Fetches the issuer's public key
- Confirms protected endpoints return
402with a challenge - Issues a batch of 1000 blinded tokens
- Verifies a token grants access and replays are rejected
npx tsx scripts/e2e-test.tsNo external services or Solana wallet required — it uses ephemeral keys in tmpdir.
Keys are auto-generated on first startup. Pre-generate with:
npx tsx scripts/setup-keys.ts # writes to .keys/ (override with KEY_DIR)Custom paths via environment variables:
| Env var | Default | Description |
|---|---|---|
SHARED_KEYS_DIR |
.keys/ |
Base directory for key files |
VOPRF_KEY_PATH |
{SHARED_KEYS_DIR}/voprf.json |
VOPRF key pair |
OHTTP_KEY_PATH |
{SHARED_KEYS_DIR}/ohttp.json |
OHTTP key pair |
In Docker, gateway and facilitator share a named volume (ppg-keys) at /app/.keys. Whichever starts first generates the keys; the second reads them.
The CLI reads the Solana keypair from ~/.ppg/payment-key.json (created by gen-payment-key). When this file exists, the CLI uses real Solana devnet payments. When it doesn't exist, payments are mocked.
private-pay gen-payment-key # create keypair at ~/.ppg/payment-key.json
private-pay fund-account # airdrop SOL on devnet
private-pay buy-tokens --gateway http://localhost:3001 # real devnet paymentThe CLI warns you which payment mode is active (mock vs Solana devnet).
npm run private-pay -- <command> [options]