feat(machine): add SQLite persistence and remove npub linking

Add crash-safe persistence for cassette inventory, cashbox state, and
transaction history using better-sqlite3 in the Electron main process.
The state machine now loads inventory from the database at runtime
instead of using hardcoded values, and transactions are automatically
persisted on completion.

Remove the unnecessary npub linking code — Lightning.Pub auto-creates
and associates Nostr users when appId is included in RPC requests,
making the HTTP-based user creation and token linking redundant.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Patrick Mulligan 2026-02-19 11:45:09 -05:00
commit f37555565e
15 changed files with 739 additions and 171 deletions

View file

@ -19,7 +19,6 @@ export interface RuntimeConfig {
atmPrivateKey: string
adminToken: string
appId: string
appToken: string
machineModel: string
fiatCode: string
validatorDevice?: string
@ -35,6 +34,21 @@ contextBridge.exposeInMainWorld('electronAPI', {
// Get runtime configuration (read from environment at runtime)
getConfig: (): Promise<RuntimeConfig> => ipcRenderer.invoke('get-config'),
// State persistence
loadCassettes: () => ipcRenderer.invoke('state:load-cassettes'),
setCassettes: (cassettes: { denomination: number; count: number }[]) =>
ipcRenderer.invoke('state:set-cassettes', cassettes),
getInventory: () => ipcRenderer.invoke('state:get-inventory'),
getCashbox: () => ipcRenderer.invoke('state:get-cashbox'),
recordTransaction: (tx: {
txid: string
type: 'cash_in' | 'cash_out'
fiatCents: number
sats: number
bills: { denomination: number; count: number }[]
}) => ipcRenderer.invoke('state:record-transaction', tx),
emptyCashbox: () => ipcRenderer.invoke('state:empty-cashbox'),
// Platform info
platform: process.platform,
})
@ -45,6 +59,22 @@ declare global {
electronAPI: {
getVersion: () => Promise<string>
getConfig: () => Promise<RuntimeConfig>
loadCassettes: () => Promise<{ denomination: number; count: number }[]>
setCassettes: (cassettes: { denomination: number; count: number }[]) => Promise<void>
getInventory: () => Promise<Record<number, number>>
getCashbox: () => Promise<{
totalBills: number
totalFiatCents: number
lastEmptiedAt: number | null
}>
recordTransaction: (tx: {
txid: string
type: 'cash_in' | 'cash_out'
fiatCents: number
sats: number
bills: { denomination: number; count: number }[]
}) => Promise<void>
emptyCashbox: () => Promise<void>
platform: NodeJS.Platform
}
}