chore(nostr-client): move dev scripts to dev/ folder

Move 9 development/testing .mjs scripts out of the package root into
dev/ to keep the published package clean. Update relative imports
and dev.sh reference.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Patrick Mulligan 2026-02-16 17:48:49 -05:00
commit 5448a620a9
10 changed files with 3 additions and 3 deletions

View file

@ -0,0 +1,182 @@
/**
* Test CLINK Debit flow
*
* This simulates what ShockWallet does when scanning an ndebit:
* 1. Decode the ndebit to get pubkey, relay, pointer
* 2. Create a bolt11 invoice (we'll get one from Alice)
* 3. Send Kind 21002 debit request to Lightning.Pub
* 4. Wait for payment response
*/
import { Relay } from 'nostr-tools/relay'
import { finalizeEvent, getPublicKey } from 'nostr-tools'
import { nip44 } from 'nostr-tools'
import { bech32 } from '@scure/base'
import { randomBytes } from 'crypto'
// Generate a random keypair for this test (simulates ShockWallet)
const WALLET_PRIVATE_KEY = randomBytes(32)
const WALLET_PUBLIC_KEY = getPublicKey(WALLET_PRIVATE_KEY)
// The ndebit to test
const NDEBIT = process.argv[2]
// The bolt11 invoice to be paid
const BOLT11 = process.argv[3]
if (!NDEBIT || !BOLT11) {
console.log('Usage: node test-debit.mjs <ndebit> <bolt11>')
console.log('')
console.log('Example:')
console.log(' # First create an invoice on Alice:')
console.log(' docker exec lamassu-lnd-alice lncli --network=regtest addinvoice --amt 1000')
console.log('')
console.log(' # Then test the debit:')
console.log(' node test-debit.mjs ndebit1... lnbcrt...')
process.exit(1)
}
function decodeNdebit(ndebit) {
const { prefix, words } = bech32.decode(ndebit, 5000)
if (prefix !== 'ndebit') throw new Error('Invalid ndebit prefix')
const data = new Uint8Array(bech32.fromWords(words))
let pubkey, relay, pointer
let offset = 0
while (offset < data.length) {
const type = data[offset]
const length = data[offset + 1]
const value = data.slice(offset + 2, offset + 2 + length)
switch (type) {
case 0:
pubkey = Buffer.from(value).toString('hex')
break
case 1:
relay = new TextDecoder().decode(value)
break
case 2:
pointer = new TextDecoder().decode(value)
break
}
offset += 2 + length
}
return { pubkey, relay, pointer }
}
async function main() {
console.log('=== CLINK Debit Test ===')
console.log('')
console.log('Test wallet pubkey:', WALLET_PUBLIC_KEY)
console.log('')
// Decode ndebit
const debit = decodeNdebit(NDEBIT)
console.log('Decoded ndebit:')
console.log(' Pubkey:', debit.pubkey)
console.log(' Relay:', debit.relay)
console.log(' Pointer:', debit.pointer || '(none)')
console.log('')
// Connect to relay (override Docker internal hostnames with localhost for local testing)
const relayUrl = debit.relay
.replace('host.docker.internal', 'localhost')
.replace('ws://strfry:', 'ws://localhost:')
console.log('Connecting to relay:', relayUrl)
const relay = await Relay.connect(relayUrl)
console.log('Connected!')
console.log('')
// Build debit request payload
const requestPayload = {
pointer: debit.pointer,
bolt11: BOLT11,
}
console.log('Request payload:', JSON.stringify(requestPayload, null, 2))
console.log('')
// Encrypt with NIP-44
const conversationKey = nip44.getConversationKey(WALLET_PRIVATE_KEY, debit.pubkey)
const encryptedContent = nip44.encrypt(JSON.stringify(requestPayload), conversationKey)
// Create Kind 21002 event
const event = finalizeEvent(
{
kind: 21002,
created_at: Math.floor(Date.now() / 1000),
tags: [
['p', debit.pubkey],
['clink_version', '1'],
],
content: encryptedContent,
},
WALLET_PRIVATE_KEY
)
console.log('Publishing debit request (event id:', event.id.substring(0, 16) + '...)...')
// Subscribe to responses
let responseReceived = false
const sub = relay.subscribe(
[
{
kinds: [21002],
authors: [debit.pubkey],
'#p': [WALLET_PUBLIC_KEY],
'#e': [event.id],
since: Math.floor(Date.now() / 1000) - 5,
},
],
{
onevent(evt) {
console.log('')
console.log('Got response event:', evt.id.substring(0, 16) + '...')
try {
const decrypted = nip44.decrypt(evt.content, conversationKey)
const response = JSON.parse(decrypted)
console.log('Response:', JSON.stringify(response, null, 2))
if (response.res === 'ok') {
console.log('')
console.log('✅ DEBIT SUCCESS!')
if (response.preimage) {
console.log('Preimage:', response.preimage)
}
} else if (response.res === 'GFY') {
console.log('')
console.log('❌ DEBIT FAILED:', response.error)
}
responseReceived = true
} catch (err) {
console.log('Failed to decrypt:', err.message)
}
},
}
)
// Publish request
await relay.publish(event)
console.log('Request published, waiting for response...')
// Wait for response
for (let i = 0; i < 30; i++) {
await new Promise((r) => setTimeout(r, 1000))
if (responseReceived) break
if (i % 5 === 4) console.log('Still waiting... (' + (i + 1) + 's)')
}
if (!responseReceived) {
console.log('')
console.log('❌ No response received within timeout')
}
sub.close()
relay.close()
}
main().catch(console.error)