Skip to content
create-bsv-app

Project structure

Every file a full-stack scaffold creates, what it does, and which ones are yours to change.

This is what --starter full-stack --capabilities wallet-login,signed-requests writes, minus create-vite's own assets and lint config. Other starters produce a subset: react is the client/ half at the project root, and express is the server/ half.

The tree#

Files
my-app/
├── AGENTS.md                      # how each capability works, for humans and AI agents
├── bsv-scaffold.json              # what was generated (read by later `add` runs)
├── package.json                   # root runner: dev, build, install:apps
├── scripts/
│   └── run-apps.mjs               # starts client + server together
├── client/                        # Vite + React + TypeScript (from create-vite)
│   ├── package.json
│   ├── vite.config.ts
│   └── src/
│       ├── main.tsx               # wraps <App/> in <WalletProviders>
│       ├── App.tsx                # routes: /, /login, /signed-demo
│       └── bsv/
│           ├── config.ts          # API_BASE_URL, BSV_NETWORK (from VITE_* env)
│           ├── apiClient.ts       # the one fetch wrapper: bounded, no redirects
│           ├── auth.ts            # createAuthProof / verifyAuthProof
│           ├── serverIdentity.ts  # getServerIdentity() → GET /api/identity
│           ├── walletAcquisition.ts      # desktop wallet via WalletClient('auto')
│           ├── WalletConnectionContext.tsx  # mobile QR relay session
│           ├── WalletContext.tsx         # useWallet(): status, wallet, identityKey
│           ├── WalletProviders.tsx       # both providers in one component
│           ├── ConnectWallet.tsx         # the button + "no wallet" dialog
│           ├── Home.tsx                  # demo hub
│           ├── WalletLogin.tsx           # /login demo        (wallet-login)
│           ├── useWalletLogin.tsx        # login() hook       (wallet-login)
│           ├── SignedRequestDemo.tsx     # /signed-demo demo  (signed-requests)
│           ├── signedRequest.ts          # createSignedRequest (signed-requests)
│           ├── useSignedRequest.ts       # signedFetch() hook (signed-requests)
│           └── bsv.css                   # minimal demo styles
└── server/                        # Express 5 + TypeScript, run with tsx
    ├── package.json
    └── src/
        ├── index.ts               # routes, CORS, wallet relay, listen()
        └── bsv/
            ├── config.ts          # SERVER_PRIVATE_KEY, PORT, CLIENT_ORIGIN, BSV_NETWORK
            ├── auth.ts            # same proof helpers as the client
            ├── nonceStore.ts      # single-use nonces (in memory)
            ├── loginRoute.ts      # POST /api/login       (wallet-login)
            └── verifySignedRequest.ts  # framework-agnostic   (signed-requests)

What runs where#

What Client Server
Dev command vite tsx watch src/index.ts
Dev URL http://localhost:5173 http://localhost:3000
Build tsc -b && vite build → client/dist tsc → server/dist
Start in production any static host node dist/index.js

From the project root, npm run dev runs both dev commands, npm run build builds both, and npm run install:apps reinstalls both. Each app also works on its own: cd client && npm run dev is fine.

Client and server are separate packages with their own package.json, lockfile and node_modules. You can deploy them to different hosts, and add a database driver to the server without touching the client.

Server routes#

Route From What it does
GET /health base { "status": "ok" } for load balancers
GET /api/identity wallet-connect the server's public identity key
GET /api/session, /ws wallet-connect mobile wallet pairing (QR relay)
POST /api/login wallet-login verifies a login proof, returns { identityKey }
POST /api/echo signed-requests verifies a signed request, echoes the signer

Which files are yours?#

All of them. Nothing is hidden in a package or framework. That said, they fall into three groups:

  • Edit freely: App.tsx, main.tsx, server/src/index.ts, Home.tsx, the demo pages and bsv.css. These are starting points, and the demo pages are there to delete.
  • Read before you edit: config.ts, apiClient.ts, auth.ts, nonceStore.ts, serverIdentity.ts. They're small but security-sensitive. See Security model for what each one guarantees.
  • Don't hand-edit: bsv-scaffold.json. Later add runs read it to decide what's already installed.
Deep diveWhy are client and server auth.ts identical?

The proof format is the same on both sides. Shipping one tiny file to each package keeps them independently deployable, with no shared workspace package and no build step. Both wrap @bsv/auth (opens in a new tab).

Read AGENTS.md next#

Every scaffold writes an AGENTS.md at the project root. For each installed capability it covers how it works, how it's used (exact function signatures and files) and future integrations. It's written for coding agents, and it's the best quick reference for humans too.