Skip to content
create-bsv-app

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.

Terminal
cd my-existing-app
npx create-bsv-app@latest add --capabilities wallet-connect,wallet-login --yes

How 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:

  1. bsv-scaffold.json. Reuses the recorded stack, folders and network, and only offers capabilities you don't have yet.
  2. A root package with react or express in its dependencies. Files go into that package's src/bsv/.
  3. client/ + server/, or frontend/ + 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:

src/main.tsx
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:

server/src/index.ts
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:

Terminal
npm i cors && npm i -D @types/cors

Re-running on a create-bsv-app project#

Run it again any time to add what you skipped:

Terminal
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.