59 lines
2.2 KiB
TypeScript
59 lines
2.2 KiB
TypeScript
// Shared "this action needs a Lightning node" gate (2026-08-02).
|
|||
|
|
//
|
||
|
|
// Creating a Lightning invoice with no Lightning node installed used to fail
|
||
|
|
// at the RPC layer — `lnd.createinvoice` returns a connection-refused error
|
||
|
|
// and the Receive screen showed it as a red failure string. That reads as the
|
||
|
|
// wallet being broken, when in fact the node simply has no Lightning
|
||
|
|
// implementation installed yet.
|
||
|
|
//
|
||
|
|
// Callers ask `requireLightningNode()` BEFORE attempting the call. When no
|
||
|
|
// node is installed it opens the global LightningRequiredModal (which offers
|
||
|
|
// to install one) and returns false, so the caller bails without surfacing an
|
||
|
|
// error at all.
|
||
|
|
//
|
||
|
|
// Detection is install-state, not reachability, on purpose: an installed node
|
||
|
|
// that is merely stopped or still starting is a different situation (wait or
|
||
|
|
// start it) and must NOT be answered with "install a Lightning node".
|
||
|
|
import { ref } from 'vue'
|
||
|
|
import { useAppStore } from '@/stores/app'
|
||
|
|
|
||
|
|
/** Package ids that provide a Lightning node.
|
||
|
|
*
|
||
|
|
* `lnd` ships today. Core Lightning is the next implementation the modal
|
||
|
|
* offers — when its app id lands in the catalog, add it here and flip its
|
||
|
|
* `available` flag in LightningRequiredModal so the same gate recognises it
|
||
|
|
* with no other change. */
|
||
|
|
export const LIGHTNING_NODE_APP_IDS = ['lnd'] as const
|
||
|
|
|
||
|
|
// Module-scope: one source of truth shared by every caller and the single
|
||
|
|
// global modal mounted in App.vue.
|
||
|
|
const show = ref(false)
|
||
|
|
|
||
|
|
export function useLightningRequired() {
|
||
|
|
const appStore = useAppStore()
|
||
|
|
|
||
|
|
/** True when some Lightning implementation is installed on this node. */
|
||
|
|
function hasLightningNode(): boolean {
|
||
|
|
const installed = Object.keys(appStore.packages ?? {})
|
||
|
|
return installed.some((pkgId) =>
|
||
|
|
(LIGHTNING_NODE_APP_IDS as readonly string[]).includes(pkgId),
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Gate a Lightning-only action. Returns true to proceed; returns false and
|
||
|
|
* opens the install modal when this node has no Lightning implementation.
|
||
|
|
*/
|
||
|
|
function requireLightningNode(): boolean {
|
||
|
|
if (hasLightningNode()) return true
|
||
|
|
show.value = true
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
function close() {
|
||
|
|
show.value = false
|
||
|
|
}
|
||
|
|
|
||
|
|
return { show, hasLightningNode, requireLightningNode, close }
|
||
|
|
}
|