Guides
Add to an existing project
Drop wallet connect, login or signed requests into a React or Express app you already have, or add more capabilities to a create-bsv-app project later.
add mode installs capability files into a project that already exists. It never runs a base generator and never edits your App.tsx, main.tsx or server entry. Instead, it writes the exact snippets to paste into AGENTS.md.
cd my-existing-app
npx create-bsv-app@latest add --capabilities wallet-connect,wallet-login --yesHow the CLI finds your app#
You don't usually need to pass --mode add. When the target folder isn't empty, the CLI looks for, in order:
bsv-scaffold.json. Reuses the recorded stack, folders and network, and only offers capabilities you don't have yet.- A root package with
reactorexpressin its dependencies. Files go into that package'ssrc/bsv/. client/+server/, orfrontend/+backend/. The first is treated as the React app, the second as the Express app.
If none of those match, the CLI assumes you meant new, and a non-empty folder stops it with target directory is not empty.
Then wire it up#
Open the regenerated AGENTS.md and find Wiring (manual). It has one block per file. Here's the client side:
import { WalletProviders } from './bsv/WalletProviders'
createRoot(document.getElementById('root')!).render(
<StrictMode>
<WalletProviders>
<App />
</WalletProviders>
</StrictMode>
)The server needs a little more#
A generated server already has a server wallet, an identity route and CORS. An existing Express app has none of them, and the AGENTS.md snippet assumes they're there. Here's a complete minimal setup. We compiled and ran this against an add-mode project:
import http from 'node:http'
import express from 'express'
import cors from 'cors'
import { PrivateKey, ProtoWallet } from '@bsv/sdk'
import { WalletRelayService } from '@bsv/wallet-relay'
import { loginRoute } from './bsv/loginRoute.js'
const CLIENT_ORIGIN = process.env.CLIENT_ORIGIN ?? 'http://localhost:5173'
const key = process.env.SERVER_PRIVATE_KEY
if (key == null && process.env.NODE_ENV === 'production') throw new Error('SERVER_PRIVATE_KEY is required in production')
// The server's own identity. Keep the key stable, or clients see a new server on every restart.
const serverWallet = new ProtoWallet(key != null ? PrivateKey.fromString(key) : PrivateKey.fromRandom())
const app = express()
app.use(cors({ origin: CLIENT_ORIGIN }))
app.use(express.json({ limit: '64kb' }))
// Clients fetch this first: it's the counterparty every proof is made for.
app.get('/api/identity', async (_req, res) => {
const { publicKey } = await serverWallet.getPublicKey({ identityKey: true })
res.json({ identityKey: publicKey })
})
app.post('/api/login', loginRoute(serverWallet))
// The mobile QR relay attaches to the raw HTTP server (it needs WebSocket upgrades).
const server = http.createServer(app)
new WalletRelayService({ app, server, wallet: serverWallet, origin: CLIENT_ORIGIN })
server.listen(Number(process.env.PORT ?? 3000))add mode puts the BSV packages in your package.json but not cors, so add it yourself:
npm i cors && npm i -D @types/corsRe-running on a create-bsv-app project#
Run it again any time to add what you skipped:
npx create-bsv-app@latest add --capabilities signed-requests --yes| What | Happens |
|---|---|
| New capability files | written |
Existing helper files in src/bsv/ |
kept, unless you pass --force |
AGENTS.md |
rewritten, with manual wiring for the new capability |
bsv-scaffold.json |
capabilities merged in |
package.json |
new dependencies added, then installed (skip with --skip-install) |
Your App.tsx, main.tsx, server/src/index.ts |
never touched |
Frameworks other than Vite and Express#
The helpers are plain TypeScript. verifySignedRequest() and verifyAuthProof() run in any Node server, and the React hooks run in any React app. The wiring snippets assume a Vite-style src/main.tsx and an Express server entry, so in Next.js, Remix, Fastify or Hono, use them as a guide rather than pasting them as is.