feat(machine): consume get_machine_config over the transport (#71)

Source the operator pubkey + fee config from LNbits via the get_machine_config
kind-21000 RPC (spirekeeper#41) right after list_wallets, instead of the
operator pubkey coming only from VITE_OPERATOR_PUBKEYS (env). A seed-only
machine (blank .env) had an empty operator allowlist → the fees/operator-config
services disabled themselves → permanent "awaiting configuration". Now it pulls
its config over the already-authenticated channel and configures itself with
zero per-machine provisioning — closing bitspire#70 P1.

- LnbitsClient.getMachineConfig() → sendRpc('get_machine_config') + the
  MachineConfigResponse / FeeConfigWire types.
- lightning.ts, only when VITE_OPERATOR_PUBKEYS is empty (env override still
  wins): set CONFIG.operatorPubkeys from operator_pubkey (re-enables the
  services), and persist fee_config via the existing applyFeeConfig IPC (mapping
  snake_case → camelCase) so atm.ts's awaiting-fees gate clears immediately —
  robust to the replaceable kind-30078 not being fetchable from the relay. The
  live kind-30078 subscription still handles mid-run fee updates.
- Soft-fail: older spirekeeper (no RPC) or a transport error falls back to the
  env/kind-30078 path.

lnbits + machine typecheck clean; lnbits suite 29 pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Padreug 2026-07-02 22:00:49 +02:00 • committed by padreug
commit fdb9a507c2
3 changed files with 79 additions and 0 deletions

View file

@ -505,6 +505,46 @@ export async function initializeLightningServices(options?: {
}
console.log('[Lightning] LNbits wallet:', lnbitsWalletId)
// #70 P1: pull operator pubkey + fee config from LNbits over the authenticated
// transport (spirekeeper#41 `get_machine_config`). A seed-only machine has no
// VITE_OPERATOR_PUBKEYS, so without this it can't trust its fee config and sits
// at "awaiting configuration". Only for the seed-only case — an explicit
// VITE_OPERATOR_PUBKEYS override keeps the env/kind-30078 path untouched.
// Soft-fail: an older spirekeeper (no RPC) or a transport error falls back to
// whatever the operator services can pull from kind-30078.
if (CONFIG.operatorPubkeys.length === 0) {
try {
const mc = await lnbits.getMachineConfig()
if (mc.operator_pubkey) {
CONFIG.operatorPubkeys = [mc.operator_pubkey]
console.log('[Lightning] Operator pubkey(s):', mc.operator_pubkey, '(server-delivered, #70 P1)')
}
if (mc.fee_config && isElectron && window.electronAPI) {
// Persist the server-delivered fee config so atm.ts's awaiting-fees gate
// (getFeeConfig) clears immediately — robust to the replaceable kind-30078
// event not being fetchable from the relay. The live kind-30078
// subscription still handles mid-run fee updates.
const applied = await window.electronAPI.applyFeeConfig(
{
cashInFeeFraction: mc.fee_config.cash_in_fee_fraction,
cashOutFeeFraction: mc.fee_config.cash_out_fee_fraction,
schemaVersion: mc.fee_config.schema_version,
},
mc.created_at,
)
console.log(
'[Lightning] Server-delivered fee config:',
applied.applied ? 'applied' : `skipped (${applied.reason})`,
)
}
} catch (e) {
console.warn(
'[Lightning] get_machine_config unavailable; falling back to env/kind-30078 for operator config:',
(e as Error).message,
)
}
}
// CLINK client — kept in tree but not actively wired into LNbits flows.
// operatorPubkey is the operator allowlist for kind-21003 management
// commands; it has no Lightning.Pub dependency.