@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.
- package/LICENSE +21 -0
- package/README.md +76 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +152 -0
- package/dist/prompts/add-feature.d.ts +16 -0
- package/dist/prompts/add-feature.js +40 -0
- package/dist/prompts/debug.d.ts +16 -0
- package/dist/prompts/debug.js +52 -0
- package/dist/prompts/integrate.d.ts +16 -0
- package/dist/prompts/integrate.js +40 -0
- package/dist/resources/api-reference.d.ts +8 -0
- package/dist/resources/api-reference.js +614 -0
- package/dist/resources/gotchas.d.ts +1 -0
- package/dist/resources/gotchas.js +188 -0
- package/dist/resources/integration.d.ts +1 -0
- package/dist/resources/integration.js +181 -0
- package/dist/resources/patterns.d.ts +1 -0
- package/dist/resources/patterns.js +266 -0
- package/dist/tools/credential.d.ts +6 -0
- package/dist/tools/credential.js +125 -0
- package/dist/tools/did.d.ts +1 -0
- package/dist/tools/did.js +166 -0
- package/dist/tools/inscription.d.ts +1 -0
- package/dist/tools/inscription.js +71 -0
- package/dist/tools/messagebox.d.ts +1 -0
- package/dist/tools/messagebox.js +85 -0
- package/dist/tools/payment.d.ts +1 -0
- package/dist/tools/payment.js +100 -0
- package/dist/tools/scaffold.d.ts +1 -0
- package/dist/tools/scaffold.js +81 -0
- package/dist/tools/server-route.d.ts +1 -0
- package/dist/tools/server-route.js +147 -0
- package/dist/tools/token.d.ts +1 -0
- package/dist/tools/token.js +92 -0
- package/dist/tools/wallet.d.ts +1 -0
- package/dist/tools/wallet.js +127 -0
- package/package.json +46 -0
|
@@ -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
|
+
`;
|