This repository is split into several runnable workspaces. The fastest way to get a fresh clone working is:
- Install the tooling you need for the workspace you are touching.
- Copy the workspace env example file(s) to the expected local file names.
- Start shared Postgres and Redis services from the repository root.
- Run the workspace's dev server or its tests.
-
Node.js and pnpm
Node and pnpm versions are pinned repo-wide. The single source of truth for the Node major is
.nvmrc(and its mirror.node-version):- Node.js 22 — read by CI (
node-version-file: .nvmrc), the Docker base images, and local version managers (nvm,fnm,mise, ...). - pnpm 9.15.9 — declared via
packageManagerin every packagepackage.jsonand enforced by pnpm; CI installs this exact version.
.npmrcsetsengine-strict=true, sopnpm installfails locally if your Node major does not match.nvmrc. Use your version manager to switch to Node 22 before installing, e.g.nvm use/fnm use. - Node.js 22 — read by CI (
-
Docker Desktop or Docker Engine with Compose v2
The repository-root Compose file provides the local infrastructure used by the backend, indexer, and oracle.
# From the repository root
cp .env.example .env
docker compose --profile deps up -dTo stop them later:
docker compose --profile deps down -vUse the root workspace only for shared Compose services and repo-level scripts.
pnpm installNo package-level dev server exists at the root; use the package-specific commands below.
cd backend
pnpm install
cp .env.example .env.local
pnpm start:dev- The backend expects local Postgres/Redis from the repository root.
- The default development port is
3001. - Run tests with:
pnpm testcd client
pnpm install
cp .env.example .env
pnpm devUse pnpm for every package root in this repository so each package has a single canonical lockfile:
- Root package: pnpm
- Client workspace: pnpm
- Backend workspace: pnpm
- SDK workspace: pnpm
- Indexer workspace: pnpm
- Oracle workspace: pnpm
Use the package manager that matches the package root you are working in. Do not add or commit npm lockfiles such as package-lock.json in these directories.
- The client uses Vite and expects the backend at
http://localhost:3001by default. - Run tests with:
pnpm testcd indexer
pnpm install
cp .env.example .env.local
pnpm start:dev- The indexer expects local Postgres/Redis from the repository root.
- Run tests with:
pnpm testcd oracle
pnpm install
cp .env.example .env.local
pnpm start:dev- The oracle expects local Redis from the repository root.
- Run tests with:
pnpm testcd sdk
pnpm install
cp examples/.env.example .env- The SDK does not require a local env file for unit tests, but the example scripts use the copied env file.
- Run tests with:
pnpm testThe repository root docker-compose.yml supports profiles for the main services:
# Shared infrastructure only
docker compose --profile deps up -d
# Backend + deps
docker compose --profile backend up -d
# Indexer + deps
docker compose --profile indexer up -d
# Oracle + deps
docker compose --profile oracle up -d
# Full stack except the client
docker compose --profile full up -d
# Full stack plus the Vite client
docker compose --profile client up -dUse the same command with down -v to tear everything down.
Unit tests run without any external services and are safe to run in CI.
The three root commands cover all five packages in one shot:
# From the repository root
pnpm lint # ESLint across all packages
pnpm test # Jest (backend / indexer / oracle / sdk) + Vitest (client)
pnpm typecheck # tsc --noEmit across all packagesAll three are wired into the husky pre-push hook, so they run automatically
before every git push. You can also run them per-workspace if you want faster
feedback while working on a single package:
# From the repository root
pnpm --dir backend test
pnpm --dir client test
pnpm --dir indexer test
pnpm --dir oracle test
pnpm --dir sdk testIntegration tests make real network calls (Stellar testnet, local backend) and are
opt-in only. They are gated behind the TEST_INTEGRATION=true environment variable
so they never run during normal test passes.
| Requirement | How to start |
|---|---|
| Stellar testnet reachable | Public endpoints are used automatically; no action needed. |
| Local backend running | cd backend && pnpm start:dev (default port 3001) |
| Local database running | docker compose --profile deps up -d |
File: sdk/src/test/sep10-integration.spec.ts
These tests cover:
- SDK SEP-10 primitives —
buildChallenge+verifyResponseexecuted against a freshly-funded Stellar testnet keypair (no backend required for this group). - Backend SIWS auth round-trip — full flow against a locally-running backend:
GET /auth/nonce→ sign message →POST /auth/verify→ assert valid JWT.
# With default backend URL (http://localhost:3001)
TEST_INTEGRATION=true pnpm --dir sdk test
# With a custom backend URL
TEST_INTEGRATION=true BACKEND_URL=http://localhost:4000 pnpm --dir sdk test
# Run only the integration spec
TEST_INTEGRATION=true pnpm --dir sdk test -- --testPathPattern=sep10-integration| Variable | Default | Description |
|---|---|---|
TEST_INTEGRATION |
false |
Set to true to enable integration tests. |
BACKEND_URL |
http://localhost:3001 |
Base URL of the locally-running backend. |
SEP10_ANCHOR_DOMAIN |
tikka.io |
Anchor domain used in challenge messages. |
- Friendbot funds a fresh testnet keypair before the suite begins.
buildChallenge+verifyResponsesucceed end-to-end.- Expired challenges are rejected with
ChallengeExpired. - Replay attacks are rejected by the in-memory nonce store.
GET /auth/noncereturns a{ nonce, issuedAt, message }payload.- Signing the message and posting to
POST /auth/verifyreturns a well-formed JWT whose payload contains the signer's Stellar address. - Wrong signature → 400.
- Replayed (already-consumed) nonce → 400.
File: sdk/src/test/rpc-integration.spec.ts
These are currently mock-based and run as part of the normal unit test suite. A future issue will convert them to use a real Soroban testnet endpoint.
The SDK enforces gzip size budgets on the read-only and light entry points via
size-limit. See sdk/README.md — Bundle size budget and size-check workflow
for current limits, how to run pnpm --filter sdk size-check, and remediation
steps when a PR grows the bundle.
pnpm --filter sdk run build:read
pnpm --filter sdk run build:light
pnpm --filter sdk run size-checkThis repository uses Prettier for code formatting. A one-time formatting sweep was performed and its commit hash is listed in .git-blame-ignore-revs so that it doesn't pollute git blame.
To configure Git to ignore this commit locally, run:
git config blame.ignoreRevsFile .git-blame-ignore-revsAll new code should be formatted with Prettier. The lint-staged hook will automatically format staged files before commit.
This repository enforces machine-readable commit messages using Conventional Commits and @commitlint/cli. This allows release tooling and CI jobs to reason about scope alongside Changesets (pnpm changeset).
<type>(<scope>): <short summary>
feat: A new featurefix: A bug fixdocs: Documentation changesstyle: Code style changes (formatting, missing semi-colons, etc.)refactor: Code changes that neither fix a bug nor add a featureperf: Performance improvementstest: Adding or updating testsbuild: Changes that affect the build system or external dependenciesci: Changes to CI configuration files and scriptschore: Other changes that don't modify src or test filesrevert: Reverts a previous commit
Scope must match one of the defined package/workspace names:
client— Frontend application (client/)sdk— Client SDK package (sdk/)backend— Backend service (backend/)indexer— Data indexer service (indexer/)oracle— Oracle service (oracle/)repo— Monorepo root, shared scripts, dependencies, or configurationdocs— Repository documentation (docs/)
Valid commit messages:
feat(client): add wallet connection state indicatorfix(sdk): resolve challenge verification timeoutdocs(repo): update release workflow documentationchore(backend): bump dependency versions
Invalid commit messages:
added new feature(missing type and scope)feat: update UI(missing scope)feat(frontend): add wallet button(invalid scopefrontend, must beclient)
- Locally: A Husky
commit-msghook validates commit messages automatically before commits are created. - CI: The
commitlintCI job validates all commit messages on pull requests and pushes tomaster.
-
pnpm lintpasses with no new errors or warnings. -
pnpm testpasses with no new failures in the workspace(s) you changed. -
pnpm typecheckpasses with no new type errors. - Commit messages follow the Conventional Commits specification with a valid scope (
client,sdk,backend,indexer,oracle,repo,docs). - New client UI strings are added to every supported locale and
pnpm --dir client check:localespasses with zero missing or orphaned keys. -
CONTRIBUTING.mdis updated if new integration test setup is required. - SDK PRs that touch public exports or read/light entry graphs:
pnpm --filter sdk size-checkpasses (see SDK bundle size section above).