@bsv/simple-mcp 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,188 @@
1
+ "use strict";
2
+ // Critical pitfalls and gotchas
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.gotchasReference = void 0;
5
+ exports.gotchasReference = `# @bsv/simple — Critical Gotchas
6
+
7
+ ## 1. basket insertion vs wallet payment are MUTUALLY EXCLUSIVE
8
+
9
+ In \`internalizeAction\`, each output can use EITHER \`basket insertion\` OR \`wallet payment\`, never both.
10
+
11
+ - **wallet payment** — provides derivation info for spending. Output is NOT in any app basket.
12
+ - **basket insertion** — puts output in a named basket (visible via \`listOutputs\`). Derivation info must go in \`customInstructions\`.
13
+
14
+ \`\`\`typescript
15
+ // CORRECT: basket insertion
16
+ await client.internalizeAction({
17
+ tx: txBytes,
18
+ outputs: [{
19
+ outputIndex: 0,
20
+ protocol: 'basket insertion',
21
+ insertionRemittance: {
22
+ basket: 'my-basket',
23
+ customInstructions: JSON.stringify({ derivationPrefix, derivationSuffix }),
24
+ tags: ['payment']
25
+ }
26
+ }]
27
+ })
28
+
29
+ // CORRECT: wallet payment
30
+ await client.internalizeAction({
31
+ tx: txBytes,
32
+ outputs: [{
33
+ outputIndex: 0,
34
+ protocol: 'wallet payment',
35
+ paymentRemittance: {
36
+ senderIdentityKey,
37
+ derivationPrefix,
38
+ derivationSuffix
39
+ }
40
+ }]
41
+ })
42
+
43
+ // WRONG: both on same output — will fail
44
+ \`\`\`
45
+
46
+ ## 2. PeerPayClient.acceptPayment() swallows errors
47
+
48
+ Returns the string \`'Unable to receive payment!'\` instead of throwing an error.
49
+
50
+ \`\`\`typescript
51
+ // WRONG: silently fails
52
+ await peerPay.acceptPayment(payment)
53
+
54
+ // CORRECT: always check
55
+ const result = await peerPay.acceptPayment(payment)
56
+ if (typeof result === 'string') throw new Error(result)
57
+ \`\`\`
58
+
59
+ The simple library handles this internally, but be aware when using \`@bsv/message-box-client\` directly.
60
+
61
+ ## 3. result.tx from createAction may be undefined
62
+
63
+ Always check before using:
64
+ \`\`\`typescript
65
+ const result = await client.createAction({ ... })
66
+ if (!result.tx) {
67
+ console.warn('No tx bytes available')
68
+ return
69
+ }
70
+ // Now safe to use result.tx
71
+ \`\`\`
72
+
73
+ ## 4. BRC-29 Payment Derivation Protocol ID
74
+
75
+ Always use: \`[2, '3241645161d8']\`
76
+ \`\`\`typescript
77
+ const protocolID: [SecurityLevel, string] = [2, '3241645161d8']
78
+ \`\`\`
79
+
80
+ ## 5. FileRevocationStore is server-only
81
+
82
+ It uses Node.js \`fs\` module and will crash in the browser. It's isolated in \`file-revocation-store.ts\` to prevent Turbopack from bundling it.
83
+
84
+ \`\`\`typescript
85
+ // Browser: use MemoryRevocationStore
86
+ import { MemoryRevocationStore } from '@bsv/simple/browser'
87
+
88
+ // Server: use FileRevocationStore
89
+ const { FileRevocationStore } = await import('@bsv/simple/server')
90
+ \`\`\`
91
+
92
+ ## 6. Overlay topics must start with tm_, services with ls_
93
+
94
+ The Overlay class enforces these prefixes and throws if violated:
95
+ \`\`\`typescript
96
+ // CORRECT
97
+ await Overlay.create({ topics: ['tm_payments'] })
98
+ await wallet.advertiseSLAP('domain.com', 'ls_payments')
99
+
100
+ // WRONG — throws Error
101
+ await Overlay.create({ topics: ['payments'] })
102
+ await wallet.advertiseSLAP('domain.com', 'payments')
103
+ \`\`\`
104
+
105
+ ## 7. Token send/redeem uses two-step signing
106
+
107
+ Token transfers require: \`createAction\` → get \`signableTransaction\` → sign with PushDrop unlock → \`signAction\`. Don't try to do it in a single step.
108
+
109
+ ## 8. pay() uses PeerPayClient.sendPayment()
110
+
111
+ Payments via \`wallet.pay()\` are routed through MessageBox P2P using PeerPayClient, not direct on-chain P2PKH. For direct on-chain payments, use \`wallet.send()\` with a P2PKH output:
112
+
113
+ \`\`\`typescript
114
+ // MessageBox P2P payment (via pay):
115
+ await wallet.pay({ to: recipientKey, satoshis: 1000 })
116
+
117
+ // Direct on-chain P2PKH (via send):
118
+ await wallet.send({
119
+ outputs: [{ to: recipientKey, satoshis: 1000 }],
120
+ description: 'Direct payment'
121
+ })
122
+ \`\`\`
123
+
124
+ ## 9. Server exports not available from @bsv/simple
125
+
126
+ Server-only utilities (ServerWallet, handler factories, FileRevocationStore, generatePrivateKey) must be imported from \`@bsv/simple/server\`, not from the main \`@bsv/simple\` entry point.
127
+
128
+ \`\`\`typescript
129
+ // WRONG
130
+ import { ServerWallet } from '@bsv/simple'
131
+
132
+ // CORRECT
133
+ import { ServerWallet } from '@bsv/simple/server'
134
+ \`\`\`
135
+
136
+ ## 10. Dynamic imports for server code in Next.js
137
+
138
+ Always use \`await import()\` for server-only code in API routes:
139
+ \`\`\`typescript
140
+ // WRONG: static import at top of API route
141
+ import { ServerWallet } from '@bsv/simple/server'
142
+
143
+ // CORRECT: dynamic import inside handler
144
+ const { ServerWallet } = await import('@bsv/simple/server')
145
+ \`\`\`
146
+
147
+ ## 11. next.config.ts serverExternalPackages is required (updated for v2)
148
+
149
+ Without this, Turbopack bundles \`@bsv/wallet-toolbox\`, \`knex\`, and database drivers for the browser:
150
+ \`\`\`typescript
151
+ const nextConfig: NextConfig = {
152
+ serverExternalPackages: [
153
+ "@bsv/wallet-toolbox", "knex", "better-sqlite3", "tedious",
154
+ "mysql", "mysql2", "pg", "pg-query-stream", "oracledb", "dotenv"
155
+ ]
156
+ }
157
+ \`\`\`
158
+
159
+ ## 12. Server wallet initialization — use handler factories
160
+
161
+ The \`createServerWalletHandler()\` factory handles lazy-init singleton + key persistence automatically. No manual caching needed:
162
+ \`\`\`typescript
163
+ // OLD (manual caching pattern — no longer needed):
164
+ // let serverWallet: any = null
165
+ // let initPromise: Promise<any> | null = null
166
+ // async function getServerWallet() { /* ... 50 lines of boilerplate ... */ }
167
+
168
+ // NEW (3 lines):
169
+ import { createServerWalletHandler } from '@bsv/simple/server'
170
+ const handler = createServerWalletHandler()
171
+ export const GET = handler.GET, POST = handler.POST
172
+ \`\`\`
173
+
174
+ Similarly, use \`createIdentityRegistryHandler()\`, \`createDIDResolverHandler()\`, and \`createCredentialIssuerHandler()\` — all handle lazy init and file persistence internally.
175
+
176
+ ## 13. No need to import @bsv/sdk
177
+
178
+ Never import \`@bsv/sdk\` in consumer code. Use \`generatePrivateKey()\` from \`@bsv/simple/server\`:
179
+ \`\`\`typescript
180
+ // WRONG
181
+ // import { PrivateKey } from '@bsv/sdk'
182
+ // const key = PrivateKey.fromRandom().toHex()
183
+
184
+ // CORRECT
185
+ import { generatePrivateKey } from '@bsv/simple/server'
186
+ const key = generatePrivateKey()
187
+ \`\`\`
188
+ `;
@@ -0,0 +1 @@
1
+ export declare const nextjsIntegrationGuide = "# @bsv/simple \u2014 Next.js Integration Guide\n\n## 1. Installation\n\n```bash\nnpm install @bsv/simple\n```\n\nNote: `@bsv/sdk` is NOT needed as a direct dependency \u2014 `@bsv/simple` wraps it entirely.\n\n## 2. next.config.ts (CRITICAL)\n\nThis is required for Turbopack to work. Without it, `@bsv/wallet-toolbox` and its database drivers will be bundled for the browser, causing build failures.\n\n```typescript\nimport type { NextConfig } from \"next\";\n\nconst nextConfig: NextConfig = {\n serverExternalPackages: [\n \"@bsv/wallet-toolbox\",\n \"knex\",\n \"better-sqlite3\",\n \"tedious\",\n \"mysql\",\n \"mysql2\",\n \"pg\",\n \"pg-query-stream\",\n \"oracledb\",\n \"dotenv\"\n ]\n};\n\nexport default nextConfig;\n```\n\n## 3. Import Patterns\n\n### Browser components (`'use client'`)\n```typescript\nimport { createWallet, Certifier, DID, Overlay } from '@bsv/simple/browser'\nimport { CredentialSchema, CredentialIssuer, MemoryRevocationStore } from '@bsv/simple/browser'\nimport type { BrowserWallet } from '@bsv/simple/browser'\n```\n\n### Server API routes (handler factories \u2014 preferred)\n```typescript\nimport { createIdentityRegistryHandler } from '@bsv/simple/server'\nimport { createDIDResolverHandler } from '@bsv/simple/server'\nimport { createServerWalletHandler } from '@bsv/simple/server'\nimport { createCredentialIssuerHandler } from '@bsv/simple/server'\n```\n\n### Server utilities (lower-level access)\n```typescript\nconst { ServerWallet, generatePrivateKey } = await import('@bsv/simple/server')\nconst { FileRevocationStore } = await import('@bsv/simple/server')\n```\n\n## 4. Browser Wallet Setup\n\n```typescript\n'use client'\nimport { useState } from 'react'\nimport { createWallet, type BrowserWallet } from '@bsv/simple/browser'\n\nexport default function Page() {\n const [wallet, setWallet] = useState<BrowserWallet | null>(null)\n const [status, setStatus] = useState('')\n\n const connect = async () => {\n try {\n const w = await createWallet()\n setWallet(w)\n setStatus(`Connected: ${w.getIdentityKey()}`)\n } catch (e) {\n setStatus(`Error: ${(e as Error).message}`)\n }\n }\n\n return (\n <div>\n <button onClick={connect}>Connect Wallet</button>\n <p>{status}</p>\n </div>\n )\n}\n```\n\n## 5. Server API Routes (Simplified)\n\nAll server routes use handler factories \u2014 no boilerplate needed:\n\n```typescript\n// app/api/identity-registry/route.ts\nimport { createIdentityRegistryHandler } from '@bsv/simple/server'\nconst handler = createIdentityRegistryHandler()\nexport const GET = handler.GET, POST = handler.POST\n```\n\n```typescript\n// app/api/resolve-did/route.ts\nimport { createDIDResolverHandler } from '@bsv/simple/server'\nconst handler = createDIDResolverHandler()\nexport const GET = handler.GET\n```\n\n```typescript\n// app/api/server-wallet/route.ts\nimport { createServerWalletHandler } from '@bsv/simple/server'\nconst handler = createServerWalletHandler()\nexport const GET = handler.GET, POST = handler.POST\n```\n\n```typescript\n// app/api/credential-issuer/route.ts (no [[...path]] needed!)\nimport { createCredentialIssuerHandler } from '@bsv/simple/server'\nconst handler = createCredentialIssuerHandler({\n schemas: [{\n id: 'my-credential',\n name: 'MyCredential',\n fields: [\n { key: 'name', label: 'Full Name', type: 'text', required: true },\n ]\n }]\n})\nexport const GET = handler.GET, POST = handler.POST\n```\n\n## 6. Server Wallet Key Persistence\n\nKey persistence is handled automatically by `createServerWalletHandler()`:\n1. `process.env.SERVER_PRIVATE_KEY` \u2014 Environment variable (production)\n2. `.server-wallet.json` file \u2014 Persisted from previous run (development)\n3. Auto-generated via `generatePrivateKey()` \u2014 Fresh key (first run)\n\nNo `@bsv/sdk` import needed. Add `.server-wallet.json` to `.gitignore`.\n\n## 7. Basket Naming Conventions\n\nUse descriptive, hyphenated names:\n- `my-app-payments` \u2014 Payment outputs\n- `my-app-tokens` \u2014 PushDrop tokens\n- `text` \u2014 Text inscriptions\n- `json` \u2014 JSON inscriptions\n- `did-chain` \u2014 DID chain UTXOs\n- `revocation-utxos` \u2014 Credential revocation\n\n## 8. Common Patterns\n\n### Auto-connect on page load\n```typescript\nuseEffect(() => {\n createWallet()\n .then(setWallet)\n .catch(() => {}) // User may not have wallet extension\n}, [])\n```\n\n### Check MessageBox handle on connect\n```typescript\nuseEffect(() => {\n if (!wallet) return\n wallet.getMessageBoxHandle('/api/identity-registry')\n .then(h => setHandle(h))\n}, [wallet])\n```\n\n### Error handling pattern\n```typescript\ntry {\n const result = await wallet.pay({ to: key, satoshis: 1000 })\n setResult(JSON.stringify(result, null, 2))\n} catch (e) {\n setError((e as Error).message)\n}\n```\n";
@@ -0,0 +1,181 @@
1
+ "use strict";
2
+ // Next.js integration guide resource
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.nextjsIntegrationGuide = void 0;
5
+ exports.nextjsIntegrationGuide = `# @bsv/simple — Next.js Integration Guide
6
+
7
+ ## 1. Installation
8
+
9
+ \`\`\`bash
10
+ npm install @bsv/simple
11
+ \`\`\`
12
+
13
+ Note: \`@bsv/sdk\` is NOT needed as a direct dependency — \`@bsv/simple\` wraps it entirely.
14
+
15
+ ## 2. next.config.ts (CRITICAL)
16
+
17
+ This is required for Turbopack to work. Without it, \`@bsv/wallet-toolbox\` and its database drivers will be bundled for the browser, causing build failures.
18
+
19
+ \`\`\`typescript
20
+ import type { NextConfig } from "next";
21
+
22
+ const nextConfig: NextConfig = {
23
+ serverExternalPackages: [
24
+ "@bsv/wallet-toolbox",
25
+ "knex",
26
+ "better-sqlite3",
27
+ "tedious",
28
+ "mysql",
29
+ "mysql2",
30
+ "pg",
31
+ "pg-query-stream",
32
+ "oracledb",
33
+ "dotenv"
34
+ ]
35
+ };
36
+
37
+ export default nextConfig;
38
+ \`\`\`
39
+
40
+ ## 3. Import Patterns
41
+
42
+ ### Browser components (\`'use client'\`)
43
+ \`\`\`typescript
44
+ import { createWallet, Certifier, DID, Overlay } from '@bsv/simple/browser'
45
+ import { CredentialSchema, CredentialIssuer, MemoryRevocationStore } from '@bsv/simple/browser'
46
+ import type { BrowserWallet } from '@bsv/simple/browser'
47
+ \`\`\`
48
+
49
+ ### Server API routes (handler factories — preferred)
50
+ \`\`\`typescript
51
+ import { createIdentityRegistryHandler } from '@bsv/simple/server'
52
+ import { createDIDResolverHandler } from '@bsv/simple/server'
53
+ import { createServerWalletHandler } from '@bsv/simple/server'
54
+ import { createCredentialIssuerHandler } from '@bsv/simple/server'
55
+ \`\`\`
56
+
57
+ ### Server utilities (lower-level access)
58
+ \`\`\`typescript
59
+ const { ServerWallet, generatePrivateKey } = await import('@bsv/simple/server')
60
+ const { FileRevocationStore } = await import('@bsv/simple/server')
61
+ \`\`\`
62
+
63
+ ## 4. Browser Wallet Setup
64
+
65
+ \`\`\`typescript
66
+ 'use client'
67
+ import { useState } from 'react'
68
+ import { createWallet, type BrowserWallet } from '@bsv/simple/browser'
69
+
70
+ export default function Page() {
71
+ const [wallet, setWallet] = useState<BrowserWallet | null>(null)
72
+ const [status, setStatus] = useState('')
73
+
74
+ const connect = async () => {
75
+ try {
76
+ const w = await createWallet()
77
+ setWallet(w)
78
+ setStatus(\`Connected: \${w.getIdentityKey()}\`)
79
+ } catch (e) {
80
+ setStatus(\`Error: \${(e as Error).message}\`)
81
+ }
82
+ }
83
+
84
+ return (
85
+ <div>
86
+ <button onClick={connect}>Connect Wallet</button>
87
+ <p>{status}</p>
88
+ </div>
89
+ )
90
+ }
91
+ \`\`\`
92
+
93
+ ## 5. Server API Routes (Simplified)
94
+
95
+ All server routes use handler factories — no boilerplate needed:
96
+
97
+ \`\`\`typescript
98
+ // app/api/identity-registry/route.ts
99
+ import { createIdentityRegistryHandler } from '@bsv/simple/server'
100
+ const handler = createIdentityRegistryHandler()
101
+ export const GET = handler.GET, POST = handler.POST
102
+ \`\`\`
103
+
104
+ \`\`\`typescript
105
+ // app/api/resolve-did/route.ts
106
+ import { createDIDResolverHandler } from '@bsv/simple/server'
107
+ const handler = createDIDResolverHandler()
108
+ export const GET = handler.GET
109
+ \`\`\`
110
+
111
+ \`\`\`typescript
112
+ // app/api/server-wallet/route.ts
113
+ import { createServerWalletHandler } from '@bsv/simple/server'
114
+ const handler = createServerWalletHandler()
115
+ export const GET = handler.GET, POST = handler.POST
116
+ \`\`\`
117
+
118
+ \`\`\`typescript
119
+ // app/api/credential-issuer/route.ts (no [[...path]] needed!)
120
+ import { createCredentialIssuerHandler } from '@bsv/simple/server'
121
+ const handler = createCredentialIssuerHandler({
122
+ schemas: [{
123
+ id: 'my-credential',
124
+ name: 'MyCredential',
125
+ fields: [
126
+ { key: 'name', label: 'Full Name', type: 'text', required: true },
127
+ ]
128
+ }]
129
+ })
130
+ export const GET = handler.GET, POST = handler.POST
131
+ \`\`\`
132
+
133
+ ## 6. Server Wallet Key Persistence
134
+
135
+ Key persistence is handled automatically by \`createServerWalletHandler()\`:
136
+ 1. \`process.env.SERVER_PRIVATE_KEY\` — Environment variable (production)
137
+ 2. \`.server-wallet.json\` file — Persisted from previous run (development)
138
+ 3. Auto-generated via \`generatePrivateKey()\` — Fresh key (first run)
139
+
140
+ No \`@bsv/sdk\` import needed. Add \`.server-wallet.json\` to \`.gitignore\`.
141
+
142
+ ## 7. Basket Naming Conventions
143
+
144
+ Use descriptive, hyphenated names:
145
+ - \`my-app-payments\` — Payment outputs
146
+ - \`my-app-tokens\` — PushDrop tokens
147
+ - \`text\` — Text inscriptions
148
+ - \`json\` — JSON inscriptions
149
+ - \`did-chain\` — DID chain UTXOs
150
+ - \`revocation-utxos\` — Credential revocation
151
+
152
+ ## 8. Common Patterns
153
+
154
+ ### Auto-connect on page load
155
+ \`\`\`typescript
156
+ useEffect(() => {
157
+ createWallet()
158
+ .then(setWallet)
159
+ .catch(() => {}) // User may not have wallet extension
160
+ }, [])
161
+ \`\`\`
162
+
163
+ ### Check MessageBox handle on connect
164
+ \`\`\`typescript
165
+ useEffect(() => {
166
+ if (!wallet) return
167
+ wallet.getMessageBoxHandle('/api/identity-registry')
168
+ .then(h => setHandle(h))
169
+ }, [wallet])
170
+ \`\`\`
171
+
172
+ ### Error handling pattern
173
+ \`\`\`typescript
174
+ try {
175
+ const result = await wallet.pay({ to: key, satoshis: 1000 })
176
+ setResult(JSON.stringify(result, null, 2))
177
+ } catch (e) {
178
+ setError((e as Error).message)
179
+ }
180
+ \`\`\`
181
+ `;
@@ -0,0 +1 @@
1
+ export declare const codePatterns = "# @bsv/simple \u2014 Common Code Patterns\n\n## Pattern 1: Connect Wallet + Auto-check MessageBox\n```typescript\n'use client'\nimport { useState, useEffect } from 'react'\nimport { createWallet, type BrowserWallet } from '@bsv/simple/browser'\n\nexport default function Page() {\n const [wallet, setWallet] = useState<BrowserWallet | null>(null)\n const [handle, setHandle] = useState<string | null>(null)\n\n const connect = async () => {\n const w = await createWallet()\n setWallet(w)\n const h = await w.getMessageBoxHandle('/api/identity-registry')\n setHandle(h)\n }\n\n return (\n <div>\n {!wallet ? (\n <button onClick={connect}>Connect Wallet</button>\n ) : (\n <div>\n <p>Connected: {wallet.getIdentityKey().substring(0, 20)}...</p>\n {handle && <p>Handle: {handle}</p>}\n </div>\n )}\n </div>\n )\n}\n```\n\n## Pattern 2: Simple Payment via MessageBox P2P\n```typescript\nconst result = await wallet.pay({\n to: recipientKey,\n satoshis: 1000\n})\n\nconsole.log('TXID:', result.txid)\n```\n\n## Pattern 3: Multi-Output Send\n```typescript\nconst result = await wallet.send({\n outputs: [\n { to: recipientKey, satoshis: 1000, basket: 'payments' },\n { data: ['Hello blockchain!'], basket: 'text' },\n { to: wallet.getIdentityKey(), data: [{ value: 42 }], satoshis: 1, basket: 'tokens' }\n ],\n description: 'Multi-output transaction'\n})\n```\n\n## Pattern 4: Token CRUD\n```typescript\n// Create\nconst token = await wallet.createToken({\n data: { type: 'loyalty', points: 100 },\n basket: 'my-tokens',\n satoshis: 1\n})\n\n// List (decrypts automatically)\nconst tokens = await wallet.listTokenDetails('my-tokens')\n\n// Send\nawait wallet.sendToken({ basket: 'my-tokens', outpoint: tokens[0].outpoint, to: recipientKey })\n\n// Redeem\nawait wallet.redeemToken({ basket: 'my-tokens', outpoint: tokens[0].outpoint })\n```\n\n## Pattern 5: Token Transfer via MessageBox\n```typescript\n// Sender\nawait wallet.sendTokenViaMessageBox({ basket: 'my-tokens', outpoint: '...', to: recipientKey })\n\n// Recipient\nconst incoming = await wallet.listIncomingTokens()\nfor (const token of incoming) {\n await wallet.acceptIncomingToken(token, 'received-tokens')\n}\n```\n\n## Pattern 6: Inscriptions\n```typescript\nconst text = await wallet.inscribeText('Hello blockchain!')\nconst json = await wallet.inscribeJSON({ title: 'Document', created: Date.now() })\nconst hash = await wallet.inscribeFileHash('a'.repeat(64))\n```\n\n## Pattern 7: MessageBox Payments\n```typescript\n// Register identity\nawait wallet.certifyForMessageBox('@alice', '/api/identity-registry')\n\n// Find recipient\nconst results = await wallet.lookupIdentityByTag('bob', '/api/identity-registry')\n\n// Send payment\nawait wallet.sendMessageBoxPayment(results[0].identityKey, 1000)\n\n// Receive payments\nconst incoming = await wallet.listIncomingPayments()\nfor (const payment of incoming) {\n await wallet.acceptIncomingPayment(payment, 'received-payments')\n}\n```\n\n## Pattern 8: Server Wallet Funding Flow\n```typescript\n// Server side: 3-line handler (app/api/server-wallet/route.ts)\n// import { createServerWalletHandler } from '@bsv/simple/server'\n// const handler = createServerWalletHandler()\n// export const GET = handler.GET, POST = handler.POST\n\n// Client side:\n// 1. Get payment request from server\nconst res = await fetch('/api/server-wallet?action=request')\nconst { paymentRequest } = await res.json()\n\n// 2. Fund server wallet\nconst result = await wallet.fundServerWallet(paymentRequest, 'server-funding')\n\n// 3. Send tx to server\nawait fetch('/api/server-wallet?action=receive', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n tx: Array.from(result.tx),\n senderIdentityKey: wallet.getIdentityKey(),\n derivationPrefix: paymentRequest.derivationPrefix,\n derivationSuffix: paymentRequest.derivationSuffix,\n outputIndex: 0\n })\n})\n```\n\n## Pattern 9: DID Operations (V2 \u2014 UTXO Chain-Linked)\n```typescript\nimport { createWallet, DID } from '@bsv/simple/browser'\n\n// Initialize with proxy for cross-wallet resolution\nconst wallet = await createWallet({ didProxyUrl: '/api/resolve-did' })\n\n// Create a DID (on-chain, UTXO chain-linked)\nconst { did, document } = await wallet.createDID()\nconsole.log(did) // 'did:bsv:<txid>'\n\n// Resolve any DID (own \u2192 local basket, others \u2192 proxy \u2192 WoC chain-following)\nconst result = await wallet.resolveDID('did:bsv:<txid>')\nif (result.didDocument) {\n console.log('Subject key:', result.didDocument.verificationMethod[0].publicKeyJwk)\n}\nif (result.didDocumentMetadata?.deactivated) {\n console.log('DID is deactivated')\n}\n\n// Update DID (adds services, extra keys)\nawait wallet.updateDID({\n did,\n services: [{ id: did + '#api', type: 'API', serviceEndpoint: 'https://...' }]\n})\n\n// List all wallet DIDs\nconst dids = await wallet.listDIDs()\ndids.forEach(d => console.log(d.did, d.status)) // 'active' or 'deactivated'\n\n// Deactivate\nawait wallet.deactivateDID(did)\n\n// Static utilities\nDID.isValid('did:bsv:<txid>') // true (64-char txid)\nDID.isValid('did:bsv:02abc...') // true (66-char legacy pubkey)\n```\n\n## Pattern 10: Issue Verifiable Credentials\n```typescript\nimport { CredentialIssuer, CredentialSchema, MemoryRevocationStore } from '@bsv/simple/browser'\n\nconst schema = new CredentialSchema({\n id: 'age-verification',\n name: 'AgeVerification',\n fields: [\n { key: 'name', label: 'Name', type: 'text', required: true },\n { key: 'over18', label: 'Over 18', type: 'checkbox', required: true }\n ]\n})\n\nconst issuer = await CredentialIssuer.create({\n privateKey: 'hex_key',\n schemas: [schema.getConfig()],\n revocation: { enabled: false }\n})\n\n// Issue\nconst vc = await issuer.issue(subjectKey, 'age-verification', { name: 'Alice', over18: 'true' })\n\n// List from wallet\nconst vcs = await wallet.listCredentials({\n certifiers: [issuer.getInfo().publicKey],\n types: [schema.getInfo().certificateTypeBase64]\n})\n\n// Create verifiable presentation\nconst vp = wallet.createPresentation(vcs)\n```\n\n## Pattern 11: Overlay Operations\n```typescript\nimport { Overlay } from '@bsv/simple/browser'\n\nconst overlay = await Overlay.create({ topics: ['tm_payments'], network: 'mainnet' })\n\n// Advertise\nawait wallet.advertiseSHIP('https://myserver.com', 'tm_payments')\nawait wallet.advertiseSLAP('https://myserver.com', 'ls_payments')\n\n// Broadcast action to overlay\nconst { txid, broadcast } = await wallet.broadcastAction(overlay, {\n outputs: [{ lockingScript: '...', satoshis: 1, outputDescription: 'Overlay output' }]\n}, ['tm_payments'])\n\n// Query\nconst results = await overlay.lookupOutputs('ls_payments', { tag: 'recent' })\n```\n\n## Pattern 12: Server API Routes (Handler Factories)\nAll server routes use handler factories \u2014 no boilerplate, no `@bsv/sdk` import needed:\n```typescript\n// app/api/identity-registry/route.ts\nimport { createIdentityRegistryHandler } from '@bsv/simple/server'\nconst handler = createIdentityRegistryHandler()\nexport const GET = handler.GET, POST = handler.POST\n\n// app/api/resolve-did/route.ts\nimport { createDIDResolverHandler } from '@bsv/simple/server'\nconst handler = createDIDResolverHandler()\nexport const GET = handler.GET\n\n// app/api/server-wallet/route.ts\nimport { createServerWalletHandler } from '@bsv/simple/server'\nconst handler = createServerWalletHandler()\nexport const GET = handler.GET, POST = handler.POST\n\n// app/api/credential-issuer/route.ts (no [[...path]] needed!)\nimport { createCredentialIssuerHandler } from '@bsv/simple/server'\nconst handler = createCredentialIssuerHandler({\n schemas: [{\n id: 'my-credential',\n name: 'MyCredential',\n fields: [\n { key: 'name', label: 'Full Name', type: 'text', required: true },\n ]\n }]\n})\nexport const GET = handler.GET, POST = handler.POST\n```\n";
@@ -0,0 +1,266 @@
1
+ "use strict";
2
+ // Common code patterns
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.codePatterns = void 0;
5
+ exports.codePatterns = `# @bsv/simple — Common Code Patterns
6
+
7
+ ## Pattern 1: Connect Wallet + Auto-check MessageBox
8
+ \`\`\`typescript
9
+ 'use client'
10
+ import { useState, useEffect } from 'react'
11
+ import { createWallet, type BrowserWallet } from '@bsv/simple/browser'
12
+
13
+ export default function Page() {
14
+ const [wallet, setWallet] = useState<BrowserWallet | null>(null)
15
+ const [handle, setHandle] = useState<string | null>(null)
16
+
17
+ const connect = async () => {
18
+ const w = await createWallet()
19
+ setWallet(w)
20
+ const h = await w.getMessageBoxHandle('/api/identity-registry')
21
+ setHandle(h)
22
+ }
23
+
24
+ return (
25
+ <div>
26
+ {!wallet ? (
27
+ <button onClick={connect}>Connect Wallet</button>
28
+ ) : (
29
+ <div>
30
+ <p>Connected: {wallet.getIdentityKey().substring(0, 20)}...</p>
31
+ {handle && <p>Handle: {handle}</p>}
32
+ </div>
33
+ )}
34
+ </div>
35
+ )
36
+ }
37
+ \`\`\`
38
+
39
+ ## Pattern 2: Simple Payment via MessageBox P2P
40
+ \`\`\`typescript
41
+ const result = await wallet.pay({
42
+ to: recipientKey,
43
+ satoshis: 1000
44
+ })
45
+
46
+ console.log('TXID:', result.txid)
47
+ \`\`\`
48
+
49
+ ## Pattern 3: Multi-Output Send
50
+ \`\`\`typescript
51
+ const result = await wallet.send({
52
+ outputs: [
53
+ { to: recipientKey, satoshis: 1000, basket: 'payments' },
54
+ { data: ['Hello blockchain!'], basket: 'text' },
55
+ { to: wallet.getIdentityKey(), data: [{ value: 42 }], satoshis: 1, basket: 'tokens' }
56
+ ],
57
+ description: 'Multi-output transaction'
58
+ })
59
+ \`\`\`
60
+
61
+ ## Pattern 4: Token CRUD
62
+ \`\`\`typescript
63
+ // Create
64
+ const token = await wallet.createToken({
65
+ data: { type: 'loyalty', points: 100 },
66
+ basket: 'my-tokens',
67
+ satoshis: 1
68
+ })
69
+
70
+ // List (decrypts automatically)
71
+ const tokens = await wallet.listTokenDetails('my-tokens')
72
+
73
+ // Send
74
+ await wallet.sendToken({ basket: 'my-tokens', outpoint: tokens[0].outpoint, to: recipientKey })
75
+
76
+ // Redeem
77
+ await wallet.redeemToken({ basket: 'my-tokens', outpoint: tokens[0].outpoint })
78
+ \`\`\`
79
+
80
+ ## Pattern 5: Token Transfer via MessageBox
81
+ \`\`\`typescript
82
+ // Sender
83
+ await wallet.sendTokenViaMessageBox({ basket: 'my-tokens', outpoint: '...', to: recipientKey })
84
+
85
+ // Recipient
86
+ const incoming = await wallet.listIncomingTokens()
87
+ for (const token of incoming) {
88
+ await wallet.acceptIncomingToken(token, 'received-tokens')
89
+ }
90
+ \`\`\`
91
+
92
+ ## Pattern 6: Inscriptions
93
+ \`\`\`typescript
94
+ const text = await wallet.inscribeText('Hello blockchain!')
95
+ const json = await wallet.inscribeJSON({ title: 'Document', created: Date.now() })
96
+ const hash = await wallet.inscribeFileHash('a'.repeat(64))
97
+ \`\`\`
98
+
99
+ ## Pattern 7: MessageBox Payments
100
+ \`\`\`typescript
101
+ // Register identity
102
+ await wallet.certifyForMessageBox('@alice', '/api/identity-registry')
103
+
104
+ // Find recipient
105
+ const results = await wallet.lookupIdentityByTag('bob', '/api/identity-registry')
106
+
107
+ // Send payment
108
+ await wallet.sendMessageBoxPayment(results[0].identityKey, 1000)
109
+
110
+ // Receive payments
111
+ const incoming = await wallet.listIncomingPayments()
112
+ for (const payment of incoming) {
113
+ await wallet.acceptIncomingPayment(payment, 'received-payments')
114
+ }
115
+ \`\`\`
116
+
117
+ ## Pattern 8: Server Wallet Funding Flow
118
+ \`\`\`typescript
119
+ // Server side: 3-line handler (app/api/server-wallet/route.ts)
120
+ // import { createServerWalletHandler } from '@bsv/simple/server'
121
+ // const handler = createServerWalletHandler()
122
+ // export const GET = handler.GET, POST = handler.POST
123
+
124
+ // Client side:
125
+ // 1. Get payment request from server
126
+ const res = await fetch('/api/server-wallet?action=request')
127
+ const { paymentRequest } = await res.json()
128
+
129
+ // 2. Fund server wallet
130
+ const result = await wallet.fundServerWallet(paymentRequest, 'server-funding')
131
+
132
+ // 3. Send tx to server
133
+ await fetch('/api/server-wallet?action=receive', {
134
+ method: 'POST',
135
+ headers: { 'Content-Type': 'application/json' },
136
+ body: JSON.stringify({
137
+ tx: Array.from(result.tx),
138
+ senderIdentityKey: wallet.getIdentityKey(),
139
+ derivationPrefix: paymentRequest.derivationPrefix,
140
+ derivationSuffix: paymentRequest.derivationSuffix,
141
+ outputIndex: 0
142
+ })
143
+ })
144
+ \`\`\`
145
+
146
+ ## Pattern 9: DID Operations (V2 — UTXO Chain-Linked)
147
+ \`\`\`typescript
148
+ import { createWallet, DID } from '@bsv/simple/browser'
149
+
150
+ // Initialize with proxy for cross-wallet resolution
151
+ const wallet = await createWallet({ didProxyUrl: '/api/resolve-did' })
152
+
153
+ // Create a DID (on-chain, UTXO chain-linked)
154
+ const { did, document } = await wallet.createDID()
155
+ console.log(did) // 'did:bsv:<txid>'
156
+
157
+ // Resolve any DID (own → local basket, others → proxy → WoC chain-following)
158
+ const result = await wallet.resolveDID('did:bsv:<txid>')
159
+ if (result.didDocument) {
160
+ console.log('Subject key:', result.didDocument.verificationMethod[0].publicKeyJwk)
161
+ }
162
+ if (result.didDocumentMetadata?.deactivated) {
163
+ console.log('DID is deactivated')
164
+ }
165
+
166
+ // Update DID (adds services, extra keys)
167
+ await wallet.updateDID({
168
+ did,
169
+ services: [{ id: did + '#api', type: 'API', serviceEndpoint: 'https://...' }]
170
+ })
171
+
172
+ // List all wallet DIDs
173
+ const dids = await wallet.listDIDs()
174
+ dids.forEach(d => console.log(d.did, d.status)) // 'active' or 'deactivated'
175
+
176
+ // Deactivate
177
+ await wallet.deactivateDID(did)
178
+
179
+ // Static utilities
180
+ DID.isValid('did:bsv:<txid>') // true (64-char txid)
181
+ DID.isValid('did:bsv:02abc...') // true (66-char legacy pubkey)
182
+ \`\`\`
183
+
184
+ ## Pattern 10: Issue Verifiable Credentials
185
+ \`\`\`typescript
186
+ import { CredentialIssuer, CredentialSchema, MemoryRevocationStore } from '@bsv/simple/browser'
187
+
188
+ const schema = new CredentialSchema({
189
+ id: 'age-verification',
190
+ name: 'AgeVerification',
191
+ fields: [
192
+ { key: 'name', label: 'Name', type: 'text', required: true },
193
+ { key: 'over18', label: 'Over 18', type: 'checkbox', required: true }
194
+ ]
195
+ })
196
+
197
+ const issuer = await CredentialIssuer.create({
198
+ privateKey: 'hex_key',
199
+ schemas: [schema.getConfig()],
200
+ revocation: { enabled: false }
201
+ })
202
+
203
+ // Issue
204
+ const vc = await issuer.issue(subjectKey, 'age-verification', { name: 'Alice', over18: 'true' })
205
+
206
+ // List from wallet
207
+ const vcs = await wallet.listCredentials({
208
+ certifiers: [issuer.getInfo().publicKey],
209
+ types: [schema.getInfo().certificateTypeBase64]
210
+ })
211
+
212
+ // Create verifiable presentation
213
+ const vp = wallet.createPresentation(vcs)
214
+ \`\`\`
215
+
216
+ ## Pattern 11: Overlay Operations
217
+ \`\`\`typescript
218
+ import { Overlay } from '@bsv/simple/browser'
219
+
220
+ const overlay = await Overlay.create({ topics: ['tm_payments'], network: 'mainnet' })
221
+
222
+ // Advertise
223
+ await wallet.advertiseSHIP('https://myserver.com', 'tm_payments')
224
+ await wallet.advertiseSLAP('https://myserver.com', 'ls_payments')
225
+
226
+ // Broadcast action to overlay
227
+ const { txid, broadcast } = await wallet.broadcastAction(overlay, {
228
+ outputs: [{ lockingScript: '...', satoshis: 1, outputDescription: 'Overlay output' }]
229
+ }, ['tm_payments'])
230
+
231
+ // Query
232
+ const results = await overlay.lookupOutputs('ls_payments', { tag: 'recent' })
233
+ \`\`\`
234
+
235
+ ## Pattern 12: Server API Routes (Handler Factories)
236
+ All server routes use handler factories — no boilerplate, no \`@bsv/sdk\` import needed:
237
+ \`\`\`typescript
238
+ // app/api/identity-registry/route.ts
239
+ import { createIdentityRegistryHandler } from '@bsv/simple/server'
240
+ const handler = createIdentityRegistryHandler()
241
+ export const GET = handler.GET, POST = handler.POST
242
+
243
+ // app/api/resolve-did/route.ts
244
+ import { createDIDResolverHandler } from '@bsv/simple/server'
245
+ const handler = createDIDResolverHandler()
246
+ export const GET = handler.GET
247
+
248
+ // app/api/server-wallet/route.ts
249
+ import { createServerWalletHandler } from '@bsv/simple/server'
250
+ const handler = createServerWalletHandler()
251
+ export const GET = handler.GET, POST = handler.POST
252
+
253
+ // app/api/credential-issuer/route.ts (no [[...path]] needed!)
254
+ import { createCredentialIssuerHandler } from '@bsv/simple/server'
255
+ const handler = createCredentialIssuerHandler({
256
+ schemas: [{
257
+ id: 'my-credential',
258
+ name: 'MyCredential',
259
+ fields: [
260
+ { key: 'name', label: 'Full Name', type: 'text', required: true },
261
+ ]
262
+ }]
263
+ })
264
+ export const GET = handler.GET, POST = handler.POST
265
+ \`\`\`
266
+ `;
@@ -0,0 +1,6 @@
1
+ export declare function generateCredentialIssuer(schemaFields: Array<{
2
+ key: string;
3
+ label: string;
4
+ type: string;
5
+ required?: boolean;
6
+ }>, revocation: boolean): string;