feat(lightning): add withdraw link lifecycle management (delete/update/invalidate)
- Add deleteWithdrawLink and updateWithdrawLink RPC methods to LightningPubClient - Extract shared WithdrawLink type, add Delete/Update request/response types - Track linkId in LNURL sessions for server-side cleanup - Invalidate previous LNURL session on new link creation - Auto-delete expired links on the server Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e48073397f
commit
99ae5ab3de
4 changed files with 132 additions and 37 deletions
|
|
@ -227,6 +227,8 @@ export { validateDebitSession, findActiveSessionByAmount, markSessionPaid, getSe
|
|||
/** Active LNURL-withdraw session */
|
||||
interface LnurlSession {
|
||||
sessionId: string
|
||||
/** Link ID for management operations (delete/update) */
|
||||
linkId: string
|
||||
uniqueHash: string
|
||||
satsAmount: number
|
||||
status: 'active' | 'claimed' | 'expired'
|
||||
|
|
@ -240,11 +242,17 @@ const lnurlSessions = new Map<string, LnurlSession>()
|
|||
/**
|
||||
* Register a new LNURL-withdraw session
|
||||
*/
|
||||
function registerLnurlSession(sessionId: string, uniqueHash: string, satsAmount: number): void {
|
||||
function registerLnurlSession(
|
||||
sessionId: string,
|
||||
linkId: string,
|
||||
uniqueHash: string,
|
||||
satsAmount: number
|
||||
): void {
|
||||
console.log('[LNURL Session] Registering:', uniqueHash, 'for', satsAmount, 'sats')
|
||||
|
||||
lnurlSessions.set(uniqueHash, {
|
||||
sessionId,
|
||||
linkId,
|
||||
uniqueHash,
|
||||
satsAmount,
|
||||
status: 'active',
|
||||
|
|
@ -258,6 +266,10 @@ function registerLnurlSession(sessionId: string, uniqueHash: string, satsAmount:
|
|||
console.log('[LNURL Session] Expiring:', uniqueHash)
|
||||
session.status = 'expired'
|
||||
if (session.cleanup) session.cleanup()
|
||||
// Delete the link on the server so it can't be claimed
|
||||
lightningPub.deleteWithdrawLink(session.linkId).catch((err) => {
|
||||
console.warn('[LNURL Session] Failed to delete expired link:', err)
|
||||
})
|
||||
// Clean up after another minute
|
||||
setTimeout(() => lnurlSessions.delete(uniqueHash), 60000)
|
||||
}
|
||||
|
|
@ -315,6 +327,26 @@ function startLnurlCompletionPolling(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate an active LNURL session by cash-in sessionId.
|
||||
* Stops polling and deletes the link on the server.
|
||||
*/
|
||||
function invalidateLnurlSessionBySessionId(sessionId: string): void {
|
||||
for (const [hash, session] of lnurlSessions.entries()) {
|
||||
if (session.sessionId === sessionId && session.status === 'active') {
|
||||
console.log('[LNURL Session] Invalidating previous session:', hash)
|
||||
session.status = 'expired'
|
||||
if (session.cleanup) session.cleanup()
|
||||
if (session.linkId) {
|
||||
lightningPub.deleteWithdrawLink(session.linkId).catch((err) => {
|
||||
console.warn('[LNURL Session] Failed to delete old link:', err)
|
||||
})
|
||||
}
|
||||
lnurlSessions.delete(hash)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Debit Approval Service
|
||||
// ============================================================================
|
||||
|
|
@ -1059,6 +1091,12 @@ function createATMServices(
|
|||
console.log('[ATM Service] Using Nostr RPC (NIP-44 encrypted)')
|
||||
|
||||
try {
|
||||
// Invalidate any previous LNURL session for this cash-in session
|
||||
// (shouldn't happen — LNURL is generated once — but guard against it)
|
||||
if (context.cashInSessionId) {
|
||||
invalidateLnurlSessionBySessionId(context.cashInSessionId)
|
||||
}
|
||||
|
||||
// Call the withdraw extension via Nostr RPC (encrypted)
|
||||
const response = await lightningPub.createWithdrawLink({
|
||||
title: `ATM Cash-In ${context.cashInSessionId?.slice(0, 8) || 'session'}`,
|
||||
|
|
@ -1074,10 +1112,17 @@ function createATMServices(
|
|||
throw new Error('RPC did not return LNURL in response')
|
||||
}
|
||||
|
||||
if (!response.link?.id) {
|
||||
console.warn(
|
||||
'[ATM Service] Withdraw link response missing id — delete/update unavailable'
|
||||
)
|
||||
}
|
||||
|
||||
// Register session for tracking completion
|
||||
if (context.cashInSessionId) {
|
||||
registerLnurlSession(
|
||||
context.cashInSessionId,
|
||||
response.link.id || '',
|
||||
response.link.unique_hash,
|
||||
context.satsAmount
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue