@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,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateCredentialIssuer = generateCredentialIssuer;
|
|
4
|
+
function generateCredentialIssuer(schemaFields, revocation) {
|
|
5
|
+
const fieldsDef = schemaFields.map(f => ` { key: '${f.key}', label: '${f.label}', type: '${f.type}'${f.required ? ', required: true' : ''} }`).join(',\n');
|
|
6
|
+
const schemaId = 'custom-credential';
|
|
7
|
+
return `\`\`\`typescript
|
|
8
|
+
import {
|
|
9
|
+
CredentialSchema,
|
|
10
|
+
CredentialIssuer,
|
|
11
|
+
${revocation ? 'MemoryRevocationStore,' : ''}
|
|
12
|
+
toVerifiableCredential,
|
|
13
|
+
toVerifiablePresentation
|
|
14
|
+
} from '@bsv/simple/browser'
|
|
15
|
+
|
|
16
|
+
// 1. Define Schema
|
|
17
|
+
const schema = new CredentialSchema({
|
|
18
|
+
id: '${schemaId}',
|
|
19
|
+
name: 'CustomCredential',
|
|
20
|
+
fields: [
|
|
21
|
+
${fieldsDef}
|
|
22
|
+
],
|
|
23
|
+
computedFields: (values) => ({
|
|
24
|
+
...values,
|
|
25
|
+
issuedAt: new Date().toISOString()
|
|
26
|
+
})
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
// 2. Create Issuer
|
|
30
|
+
const issuer = await CredentialIssuer.create({
|
|
31
|
+
privateKey: issuerPrivateKeyHex,
|
|
32
|
+
schemas: [schema.getConfig()],
|
|
33
|
+
revocation: {
|
|
34
|
+
enabled: ${revocation},
|
|
35
|
+
${revocation ? `wallet: issuerWallet.getClient(),
|
|
36
|
+
store: new MemoryRevocationStore()` : ''}
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
console.log('Issuer DID:', issuer.getInfo().did)
|
|
41
|
+
|
|
42
|
+
// 3. Issue a Credential
|
|
43
|
+
async function issueCredential(
|
|
44
|
+
subjectKey: string,
|
|
45
|
+
fields: Record<string, string>
|
|
46
|
+
): Promise<VerifiableCredential> {
|
|
47
|
+
// Validate fields
|
|
48
|
+
const error = schema.validate(fields)
|
|
49
|
+
if (error) throw new Error(error)
|
|
50
|
+
|
|
51
|
+
// Issue
|
|
52
|
+
const vc = await issuer.issue(subjectKey, '${schemaId}', fields)
|
|
53
|
+
console.log('VC issued to:', vc.credentialSubject.id)
|
|
54
|
+
return vc
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 4. Verify a Credential
|
|
58
|
+
async function verifyCredential(vc: VerifiableCredential) {
|
|
59
|
+
const result = await issuer.verify(vc)
|
|
60
|
+
console.log('Valid:', result.valid, '| Revoked:', result.revoked)
|
|
61
|
+
if (result.errors.length) console.warn('Errors:', result.errors)
|
|
62
|
+
return result
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
${revocation ? `// 5. Revoke a Credential
|
|
66
|
+
async function revokeCredential(serialNumber: string) {
|
|
67
|
+
const { txid } = await issuer.revoke(serialNumber)
|
|
68
|
+
console.log('Revoked, txid:', txid)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// 6. Check Revocation Status
|
|
72
|
+
async function checkRevocation(serialNumber: string) {
|
|
73
|
+
const revoked = await issuer.isRevoked(serialNumber)
|
|
74
|
+
console.log('Is revoked:', revoked)
|
|
75
|
+
return revoked
|
|
76
|
+
}` : ''}
|
|
77
|
+
|
|
78
|
+
// Wallet-side: Acquire + List + Present
|
|
79
|
+
async function acquireAndPresent(wallet: BrowserWallet, serverUrl: string) {
|
|
80
|
+
// Acquire from remote issuer (uses ?action=info and ?action=certify query params)
|
|
81
|
+
const vc = await wallet.acquireCredential({
|
|
82
|
+
serverUrl,
|
|
83
|
+
schemaId: '${schemaId}',
|
|
84
|
+
replaceExisting: true
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
// List credentials
|
|
88
|
+
const vcs = await wallet.listCredentials({
|
|
89
|
+
certifiers: [issuer.getInfo().publicKey],
|
|
90
|
+
types: [schema.getInfo().certificateTypeBase64]
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
// Create presentation
|
|
94
|
+
const vp = wallet.createPresentation(vcs)
|
|
95
|
+
console.log('VP holder:', vp.holder)
|
|
96
|
+
console.log('VCs in presentation:', vp.verifiableCredential.length)
|
|
97
|
+
|
|
98
|
+
return vp
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ---- Server-Side Route (REQUIRED for remote issuance) ----
|
|
102
|
+
// Use the handler factory — do NOT write manual route code:
|
|
103
|
+
|
|
104
|
+
// app/api/credential-issuer/route.ts (no [[...path]] catch-all needed!)
|
|
105
|
+
import { createCredentialIssuerHandler } from '@bsv/simple/server'
|
|
106
|
+
const handler = createCredentialIssuerHandler({
|
|
107
|
+
schemas: [{
|
|
108
|
+
id: '${schemaId}',
|
|
109
|
+
name: 'CustomCredential',
|
|
110
|
+
fields: [
|
|
111
|
+
${fieldsDef}
|
|
112
|
+
]
|
|
113
|
+
}]
|
|
114
|
+
})
|
|
115
|
+
export const GET = handler.GET, POST = handler.POST
|
|
116
|
+
|
|
117
|
+
// API endpoints (all query-param based):
|
|
118
|
+
// GET ?action=info → { certifierPublicKey, certificateType, schemas }
|
|
119
|
+
// GET ?action=schema&id=... → schema details
|
|
120
|
+
// POST ?action=certify → CertificateData (wallet acquisition)
|
|
121
|
+
// POST ?action=issue → { credential: VerifiableCredential }
|
|
122
|
+
// POST ?action=verify → { verification: VerificationResult }
|
|
123
|
+
// POST ?action=revoke → { txid }
|
|
124
|
+
\`\`\``;
|
|
125
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function generateDIDIntegration(features: string[]): string;
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateDIDIntegration = generateDIDIntegration;
|
|
4
|
+
function generateDIDIntegration(features) {
|
|
5
|
+
const sections = [];
|
|
6
|
+
sections.push(`\`\`\`typescript
|
|
7
|
+
import { createWallet, DID } from '@bsv/simple/browser'
|
|
8
|
+
\`\`\``);
|
|
9
|
+
if (features.includes('create')) {
|
|
10
|
+
sections.push(`### Create a DID (UTXO Chain-Linked)
|
|
11
|
+
\`\`\`typescript
|
|
12
|
+
async function createDID(wallet: BrowserWallet) {
|
|
13
|
+
const result = await wallet.createDID()
|
|
14
|
+
console.log('DID:', result.did) // 'did:bsv:<txid>'
|
|
15
|
+
console.log('Document:', result.document) // W3C DID Document
|
|
16
|
+
console.log('Identity Code:', result.identityCode)
|
|
17
|
+
return result
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// With services
|
|
21
|
+
async function createDIDWithServices(wallet: BrowserWallet) {
|
|
22
|
+
const result = await wallet.createDID({
|
|
23
|
+
services: [
|
|
24
|
+
{
|
|
25
|
+
id: 'did:bsv:<txid>#messaging',
|
|
26
|
+
type: 'MessagingService',
|
|
27
|
+
serviceEndpoint: 'https://example.com/messages'
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
})
|
|
31
|
+
return result
|
|
32
|
+
}
|
|
33
|
+
\`\`\``);
|
|
34
|
+
}
|
|
35
|
+
if (features.includes('resolve')) {
|
|
36
|
+
sections.push(`### Resolve a DID (Cross-Wallet)
|
|
37
|
+
|
|
38
|
+
**Important:** Cross-wallet resolution requires a server-side proxy in browser
|
|
39
|
+
environments. Set \`didProxyUrl\` when creating the wallet:
|
|
40
|
+
|
|
41
|
+
\`\`\`typescript
|
|
42
|
+
// Initialize wallet with proxy URL for cross-wallet resolution
|
|
43
|
+
const wallet = await createWallet({
|
|
44
|
+
didProxyUrl: '/api/resolve-did'
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
async function resolveDID(wallet: BrowserWallet, didString: string) {
|
|
48
|
+
if (!DID.isValid(didString)) {
|
|
49
|
+
throw new Error('Invalid DID format')
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const result = await wallet.resolveDID(didString)
|
|
53
|
+
|
|
54
|
+
if (result.didDocumentMetadata?.deactivated) {
|
|
55
|
+
console.log('DID is deactivated')
|
|
56
|
+
return null
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (result.didResolutionMetadata?.error) {
|
|
60
|
+
console.error('Resolution error:', result.didResolutionMetadata.message)
|
|
61
|
+
return null
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
console.log('Resolved DID:', result.didDocument?.id)
|
|
65
|
+
console.log('Verification Key:', result.didDocument?.verificationMethod[0]?.publicKeyJwk)
|
|
66
|
+
console.log('Created:', result.didDocumentMetadata?.created)
|
|
67
|
+
console.log('Updated:', result.didDocumentMetadata?.updated)
|
|
68
|
+
return result.didDocument
|
|
69
|
+
}
|
|
70
|
+
\`\`\`
|
|
71
|
+
|
|
72
|
+
#### Resolution Proxy (Next.js API Route)
|
|
73
|
+
|
|
74
|
+
Use the handler factory — **do NOT write manual proxy code**:
|
|
75
|
+
|
|
76
|
+
\`\`\`typescript
|
|
77
|
+
// app/api/resolve-did/route.ts
|
|
78
|
+
import { createDIDResolverHandler } from '@bsv/simple/server'
|
|
79
|
+
const handler = createDIDResolverHandler()
|
|
80
|
+
export const GET = handler.GET
|
|
81
|
+
\`\`\`
|
|
82
|
+
|
|
83
|
+
The handler automatically:
|
|
84
|
+
- Tries the nChain Universal Resolver first (10s timeout)
|
|
85
|
+
- Falls back to WoC UTXO chain-following on failure
|
|
86
|
+
- Handles deactivated DIDs
|
|
87
|
+
- Limits chain hops to 100
|
|
88
|
+
|
|
89
|
+
**Custom config (optional):**
|
|
90
|
+
\`\`\`typescript
|
|
91
|
+
createDIDResolverHandler({
|
|
92
|
+
resolverUrl: 'https://custom-resolver.com',
|
|
93
|
+
wocBaseUrl: 'https://api.whatsonchain.com',
|
|
94
|
+
resolverTimeout: 10000,
|
|
95
|
+
maxHops: 100
|
|
96
|
+
})
|
|
97
|
+
\`\`\``);
|
|
98
|
+
}
|
|
99
|
+
if (features.includes('update')) {
|
|
100
|
+
sections.push(`### Update a DID
|
|
101
|
+
\`\`\`typescript
|
|
102
|
+
async function updateDID(wallet: BrowserWallet, did: string) {
|
|
103
|
+
const result = await wallet.updateDID({
|
|
104
|
+
did,
|
|
105
|
+
services: [
|
|
106
|
+
{
|
|
107
|
+
id: did + '#api',
|
|
108
|
+
type: 'APIService',
|
|
109
|
+
serviceEndpoint: 'https://api.example.com'
|
|
110
|
+
}
|
|
111
|
+
],
|
|
112
|
+
additionalKeys: ['03abc...'] // Optional extra verification keys
|
|
113
|
+
})
|
|
114
|
+
console.log('Updated DID:', result.did)
|
|
115
|
+
console.log('New Document:', result.document)
|
|
116
|
+
return result
|
|
117
|
+
}
|
|
118
|
+
\`\`\``);
|
|
119
|
+
}
|
|
120
|
+
if (features.includes('deactivate')) {
|
|
121
|
+
sections.push(`### Deactivate (Revoke) a DID
|
|
122
|
+
\`\`\`typescript
|
|
123
|
+
async function deactivateDID(wallet: BrowserWallet, did: string) {
|
|
124
|
+
const { txid } = await wallet.deactivateDID(did)
|
|
125
|
+
console.log('Deactivated in TX:', txid)
|
|
126
|
+
// Resolving this DID will now return { didDocumentMetadata: { deactivated: true } }
|
|
127
|
+
}
|
|
128
|
+
\`\`\``);
|
|
129
|
+
}
|
|
130
|
+
if (features.includes('list')) {
|
|
131
|
+
sections.push(`### List Wallet DIDs
|
|
132
|
+
\`\`\`typescript
|
|
133
|
+
async function listDIDs(wallet: BrowserWallet) {
|
|
134
|
+
const dids = await wallet.listDIDs()
|
|
135
|
+
for (const entry of dids) {
|
|
136
|
+
console.log(entry.did, entry.status) // 'active' or 'deactivated'
|
|
137
|
+
}
|
|
138
|
+
return dids
|
|
139
|
+
}
|
|
140
|
+
\`\`\``);
|
|
141
|
+
}
|
|
142
|
+
// Legacy support
|
|
143
|
+
if (features.includes('get')) {
|
|
144
|
+
sections.push(`### Get Legacy DID (deprecated)
|
|
145
|
+
\`\`\`typescript
|
|
146
|
+
// Legacy identity-key-based DID — use createDID() for new projects
|
|
147
|
+
function getWalletDID(wallet: BrowserWallet) {
|
|
148
|
+
const didDoc = wallet.getDID()
|
|
149
|
+
console.log('DID:', didDoc.id) // 'did:bsv:02abc...' (66-char pubkey)
|
|
150
|
+
return didDoc
|
|
151
|
+
}
|
|
152
|
+
\`\`\``);
|
|
153
|
+
}
|
|
154
|
+
if (features.includes('register')) {
|
|
155
|
+
sections.push(`### Register Legacy DID (deprecated)
|
|
156
|
+
\`\`\`typescript
|
|
157
|
+
// Legacy: persist identity-key DID as certificate — use createDID() for new projects
|
|
158
|
+
async function registerDID(wallet: BrowserWallet) {
|
|
159
|
+
const didDoc = await wallet.registerDID({ persist: true })
|
|
160
|
+
console.log('DID registered:', didDoc.id)
|
|
161
|
+
return didDoc
|
|
162
|
+
}
|
|
163
|
+
\`\`\``);
|
|
164
|
+
}
|
|
165
|
+
return sections.join('\n\n');
|
|
166
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function generateInscriptionHandler(types: string[]): string;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateInscriptionHandler = generateInscriptionHandler;
|
|
4
|
+
function generateInscriptionHandler(types) {
|
|
5
|
+
const sections = [];
|
|
6
|
+
if (types.includes('text')) {
|
|
7
|
+
sections.push(`### Text Inscription
|
|
8
|
+
\`\`\`typescript
|
|
9
|
+
async function inscribeText(wallet: BrowserWallet, text: string) {
|
|
10
|
+
const result = await wallet.inscribeText(text)
|
|
11
|
+
console.log('Text inscribed:', result.txid)
|
|
12
|
+
console.log('Size:', result.dataSize, 'bytes | Basket:', result.basket)
|
|
13
|
+
return result
|
|
14
|
+
}
|
|
15
|
+
\`\`\``);
|
|
16
|
+
}
|
|
17
|
+
if (types.includes('json')) {
|
|
18
|
+
sections.push(`### JSON Inscription
|
|
19
|
+
\`\`\`typescript
|
|
20
|
+
async function inscribeJSON(wallet: BrowserWallet, data: object) {
|
|
21
|
+
const result = await wallet.inscribeJSON(data)
|
|
22
|
+
console.log('JSON inscribed:', result.txid)
|
|
23
|
+
console.log('Size:', result.dataSize, 'bytes | Basket:', result.basket)
|
|
24
|
+
return result
|
|
25
|
+
}
|
|
26
|
+
\`\`\``);
|
|
27
|
+
}
|
|
28
|
+
if (types.includes('file-hash')) {
|
|
29
|
+
sections.push(`### File Hash Inscription
|
|
30
|
+
\`\`\`typescript
|
|
31
|
+
async function inscribeFileHash(wallet: BrowserWallet, file: File) {
|
|
32
|
+
// Compute SHA-256 hash of the file
|
|
33
|
+
const buffer = await file.arrayBuffer()
|
|
34
|
+
const hashBuffer = await crypto.subtle.digest('SHA-256', buffer)
|
|
35
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer))
|
|
36
|
+
const hash = hashArray.map(b => b.toString(16).padStart(2, '0')).join('')
|
|
37
|
+
|
|
38
|
+
const result = await wallet.inscribeFileHash(hash, {
|
|
39
|
+
description: \`Hash of \${file.name}\`
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
console.log('File hash inscribed:', result.txid)
|
|
43
|
+
console.log('Hash:', hash)
|
|
44
|
+
return { ...result, hash, fileName: file.name }
|
|
45
|
+
}
|
|
46
|
+
\`\`\``);
|
|
47
|
+
}
|
|
48
|
+
if (types.includes('image-hash')) {
|
|
49
|
+
sections.push(`### Image Hash Inscription
|
|
50
|
+
\`\`\`typescript
|
|
51
|
+
async function inscribeImageHash(wallet: BrowserWallet, imageFile: File) {
|
|
52
|
+
if (!imageFile.type.startsWith('image/')) {
|
|
53
|
+
throw new Error('File must be an image')
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const buffer = await imageFile.arrayBuffer()
|
|
57
|
+
const hashBuffer = await crypto.subtle.digest('SHA-256', buffer)
|
|
58
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer))
|
|
59
|
+
const hash = hashArray.map(b => b.toString(16).padStart(2, '0')).join('')
|
|
60
|
+
|
|
61
|
+
const result = await wallet.inscribeImageHash(hash, {
|
|
62
|
+
description: \`Hash of image \${imageFile.name}\`
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
console.log('Image hash inscribed:', result.txid)
|
|
66
|
+
return { ...result, hash, fileName: imageFile.name }
|
|
67
|
+
}
|
|
68
|
+
\`\`\``);
|
|
69
|
+
}
|
|
70
|
+
return sections.join('\n\n');
|
|
71
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function generateMessageBoxSetup(features: string[], registryUrl?: string): string;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateMessageBoxSetup = generateMessageBoxSetup;
|
|
4
|
+
function generateMessageBoxSetup(features, registryUrl) {
|
|
5
|
+
const registry = registryUrl || '/api/identity-registry';
|
|
6
|
+
const sections = [];
|
|
7
|
+
if (features.includes('certify')) {
|
|
8
|
+
sections.push(`### MessageBox Certification
|
|
9
|
+
\`\`\`typescript
|
|
10
|
+
async function certifyIdentity(wallet: BrowserWallet, handle: string) {
|
|
11
|
+
// Check if already certified
|
|
12
|
+
const existingHandle = await wallet.getMessageBoxHandle('${registry}')
|
|
13
|
+
if (existingHandle) {
|
|
14
|
+
console.log('Already certified as:', existingHandle)
|
|
15
|
+
return existingHandle
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Register new handle
|
|
19
|
+
const result = await wallet.certifyForMessageBox(handle, '${registry}')
|
|
20
|
+
console.log('Certified as:', result.handle)
|
|
21
|
+
return result.handle
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function revokeIdentity(wallet: BrowserWallet) {
|
|
25
|
+
await wallet.revokeMessageBoxCertification('${registry}')
|
|
26
|
+
console.log('Identity revoked')
|
|
27
|
+
}
|
|
28
|
+
\`\`\``);
|
|
29
|
+
}
|
|
30
|
+
if (features.includes('send')) {
|
|
31
|
+
sections.push(`### Send Payment via MessageBox
|
|
32
|
+
\`\`\`typescript
|
|
33
|
+
async function sendPayment(wallet: BrowserWallet, recipientKey: string, satoshis: number) {
|
|
34
|
+
const result = await wallet.sendMessageBoxPayment(recipientKey, satoshis)
|
|
35
|
+
|
|
36
|
+
console.log('Payment sent:', result.amount, 'sats to', result.recipient)
|
|
37
|
+
|
|
38
|
+
return result
|
|
39
|
+
}
|
|
40
|
+
\`\`\``);
|
|
41
|
+
}
|
|
42
|
+
if (features.includes('receive')) {
|
|
43
|
+
sections.push(`### Receive Payments from MessageBox
|
|
44
|
+
\`\`\`typescript
|
|
45
|
+
async function receivePayments(wallet: BrowserWallet, basket = 'received-payments') {
|
|
46
|
+
const incoming = await wallet.listIncomingPayments()
|
|
47
|
+
console.log(\`\${incoming.length} incoming payments\`)
|
|
48
|
+
|
|
49
|
+
const results = []
|
|
50
|
+
for (const payment of incoming) {
|
|
51
|
+
try {
|
|
52
|
+
const accepted = await wallet.acceptIncomingPayment(payment, basket)
|
|
53
|
+
results.push({ success: true, payment: accepted })
|
|
54
|
+
} catch (e) {
|
|
55
|
+
results.push({ success: false, error: (e as Error).message })
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return results
|
|
60
|
+
}
|
|
61
|
+
\`\`\``);
|
|
62
|
+
}
|
|
63
|
+
if (features.includes('search')) {
|
|
64
|
+
sections.push(`### Search Identity Registry
|
|
65
|
+
\`\`\`typescript
|
|
66
|
+
async function searchIdentity(wallet: BrowserWallet, query: string) {
|
|
67
|
+
const results = await wallet.lookupIdentityByTag(query, '${registry}')
|
|
68
|
+
console.log(\`Found \${results.length} matches for "\${query}"\`)
|
|
69
|
+
|
|
70
|
+
for (const match of results) {
|
|
71
|
+
console.log(\` \${match.tag} → \${match.identityKey.substring(0, 20)}...\`)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return results
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function listMyTags(wallet: BrowserWallet) {
|
|
78
|
+
const tags = await wallet.listMyTags('${registry}')
|
|
79
|
+
console.log('My tags:', tags.map(t => t.tag))
|
|
80
|
+
return tags
|
|
81
|
+
}
|
|
82
|
+
\`\`\``);
|
|
83
|
+
}
|
|
84
|
+
return sections.join('\n\n');
|
|
85
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function generatePaymentHandler(type: string, basket?: string): string;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generatePaymentHandler = generatePaymentHandler;
|
|
4
|
+
function generatePaymentHandler(type, basket) {
|
|
5
|
+
const effectiveBasket = basket || 'payments';
|
|
6
|
+
if (type === 'simple') {
|
|
7
|
+
return `\`\`\`typescript
|
|
8
|
+
async function sendPayment(
|
|
9
|
+
wallet: BrowserWallet,
|
|
10
|
+
recipientKey: string,
|
|
11
|
+
satoshis: number
|
|
12
|
+
) {
|
|
13
|
+
const result = await wallet.pay({
|
|
14
|
+
to: recipientKey,
|
|
15
|
+
satoshis
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
console.log('TXID:', result.txid)
|
|
19
|
+
|
|
20
|
+
return result
|
|
21
|
+
}
|
|
22
|
+
\`\`\``;
|
|
23
|
+
}
|
|
24
|
+
if (type === 'multi-output') {
|
|
25
|
+
return `\`\`\`typescript
|
|
26
|
+
async function sendMultiOutput(
|
|
27
|
+
wallet: BrowserWallet,
|
|
28
|
+
outputs: Array<{
|
|
29
|
+
to?: string
|
|
30
|
+
satoshis?: number
|
|
31
|
+
data?: (string | object | number[])[]
|
|
32
|
+
basket?: string
|
|
33
|
+
}>
|
|
34
|
+
) {
|
|
35
|
+
const result = await wallet.send({
|
|
36
|
+
outputs: outputs.map(o => ({
|
|
37
|
+
to: o.to,
|
|
38
|
+
satoshis: o.satoshis,
|
|
39
|
+
data: o.data,
|
|
40
|
+
basket: o.basket || '${effectiveBasket}'
|
|
41
|
+
})),
|
|
42
|
+
description: 'Multi-output transaction'
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
console.log('TXID:', result.txid)
|
|
46
|
+
console.log('Outputs:', result.outputDetails.map(d => \`#\${d.index}: \${d.type} (\${d.satoshis} sats)\`))
|
|
47
|
+
|
|
48
|
+
return result
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Usage:
|
|
52
|
+
// await sendMultiOutput(wallet, [
|
|
53
|
+
// { to: recipientKey, satoshis: 1000 }, // P2PKH
|
|
54
|
+
// { data: ['Hello!'] }, // OP_RETURN
|
|
55
|
+
// { to: wallet.getIdentityKey(), data: [{ v: 1 }], satoshis: 1 } // PushDrop
|
|
56
|
+
// ])
|
|
57
|
+
\`\`\``;
|
|
58
|
+
}
|
|
59
|
+
if (type === 'server-funding') {
|
|
60
|
+
return `\`\`\`typescript
|
|
61
|
+
async function fundServer(wallet: BrowserWallet, serverApiUrl: string) {
|
|
62
|
+
// 1. Get payment request from server
|
|
63
|
+
const res = await fetch(\`\${serverApiUrl}?action=request\`)
|
|
64
|
+
const { paymentRequest } = await res.json()
|
|
65
|
+
|
|
66
|
+
// 2. Fund server wallet via BRC-29 derivation
|
|
67
|
+
const result = await wallet.fundServerWallet(
|
|
68
|
+
paymentRequest,
|
|
69
|
+
'${effectiveBasket}'
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
if (!result.tx) {
|
|
73
|
+
throw new Error('No transaction bytes returned')
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// 3. Send tx to server for internalization
|
|
77
|
+
const receiveRes = await fetch(\`\${serverApiUrl}?action=receive\`, {
|
|
78
|
+
method: 'POST',
|
|
79
|
+
headers: { 'Content-Type': 'application/json' },
|
|
80
|
+
body: JSON.stringify({
|
|
81
|
+
tx: Array.from(result.tx),
|
|
82
|
+
senderIdentityKey: wallet.getIdentityKey(),
|
|
83
|
+
derivationPrefix: paymentRequest.derivationPrefix,
|
|
84
|
+
derivationSuffix: paymentRequest.derivationSuffix,
|
|
85
|
+
outputIndex: 0
|
|
86
|
+
})
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
const receiveData = await receiveRes.json()
|
|
90
|
+
if (!receiveData.success) {
|
|
91
|
+
throw new Error(receiveData.error || 'Server receive failed')
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
console.log('Server funded:', result.txid)
|
|
95
|
+
return result
|
|
96
|
+
}
|
|
97
|
+
\`\`\``;
|
|
98
|
+
}
|
|
99
|
+
return `Unknown payment type: ${type}. Use 'simple', 'multi-output', or 'server-funding'.`;
|
|
100
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function scaffoldNextjsConfig(features: string[]): string;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.scaffoldNextjsConfig = scaffoldNextjsConfig;
|
|
4
|
+
function scaffoldNextjsConfig(features) {
|
|
5
|
+
const deps = {
|
|
6
|
+
'@bsv/simple': '^0.2.3'
|
|
7
|
+
};
|
|
8
|
+
const nextConfig = `import type { NextConfig } from "next";
|
|
9
|
+
|
|
10
|
+
const nextConfig: NextConfig = {
|
|
11
|
+
serverExternalPackages: [
|
|
12
|
+
"@bsv/wallet-toolbox",
|
|
13
|
+
"knex",
|
|
14
|
+
"better-sqlite3",
|
|
15
|
+
"tedious",
|
|
16
|
+
"mysql",
|
|
17
|
+
"mysql2",
|
|
18
|
+
"pg",
|
|
19
|
+
"pg-query-stream",
|
|
20
|
+
"oracledb",
|
|
21
|
+
"dotenv"
|
|
22
|
+
]
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export default nextConfig;`;
|
|
26
|
+
const packageAdditions = JSON.stringify({ dependencies: deps }, null, 2);
|
|
27
|
+
return `## next.config.ts
|
|
28
|
+
|
|
29
|
+
\`\`\`typescript
|
|
30
|
+
${nextConfig}
|
|
31
|
+
\`\`\`
|
|
32
|
+
|
|
33
|
+
## package.json additions
|
|
34
|
+
|
|
35
|
+
\`\`\`json
|
|
36
|
+
${packageAdditions}
|
|
37
|
+
\`\`\`
|
|
38
|
+
|
|
39
|
+
## .gitignore additions
|
|
40
|
+
|
|
41
|
+
\`\`\`
|
|
42
|
+
.server-wallet.json
|
|
43
|
+
.revocation-secrets.json
|
|
44
|
+
.identity-registry.json
|
|
45
|
+
.credential-issuer-key.json
|
|
46
|
+
\`\`\`
|
|
47
|
+
|
|
48
|
+
## Features configured: ${features.join(', ')}
|
|
49
|
+
|
|
50
|
+
${features.includes('server-wallet') ? `### Server wallet setup
|
|
51
|
+
\`\`\`typescript
|
|
52
|
+
// app/api/server-wallet/route.ts
|
|
53
|
+
import { createServerWalletHandler } from '@bsv/simple/server'
|
|
54
|
+
const handler = createServerWalletHandler()
|
|
55
|
+
export const GET = handler.GET, POST = handler.POST
|
|
56
|
+
\`\`\`` : ''}
|
|
57
|
+
${features.includes('messagebox') ? `### MessageBox setup
|
|
58
|
+
\`\`\`typescript
|
|
59
|
+
// app/api/identity-registry/route.ts
|
|
60
|
+
import { createIdentityRegistryHandler } from '@bsv/simple/server'
|
|
61
|
+
const handler = createIdentityRegistryHandler()
|
|
62
|
+
export const GET = handler.GET, POST = handler.POST
|
|
63
|
+
\`\`\`` : ''}
|
|
64
|
+
${features.includes('did') ? `### DID Resolution Proxy
|
|
65
|
+
\`\`\`typescript
|
|
66
|
+
// app/api/resolve-did/route.ts
|
|
67
|
+
import { createDIDResolverHandler } from '@bsv/simple/server'
|
|
68
|
+
const handler = createDIDResolverHandler()
|
|
69
|
+
export const GET = handler.GET
|
|
70
|
+
\`\`\`` : ''}
|
|
71
|
+
${features.includes('credentials') ? `### Credential Issuer
|
|
72
|
+
\`\`\`typescript
|
|
73
|
+
// app/api/credential-issuer/route.ts
|
|
74
|
+
import { createCredentialIssuerHandler } from '@bsv/simple/server'
|
|
75
|
+
const handler = createCredentialIssuerHandler({
|
|
76
|
+
schemas: [{ id: 'my-cred', name: 'MyCred', fields: [{ key: 'name', label: 'Name', type: 'text', required: true }] }]
|
|
77
|
+
})
|
|
78
|
+
export const GET = handler.GET, POST = handler.POST
|
|
79
|
+
\`\`\`` : ''}
|
|
80
|
+
`;
|
|
81
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function generateServerRoute(routeType: string): string;
|