feat(machine): NFC Bolt Card reader driver + IPC (main process)
Main-process driver over nfc-pcsc (PC/SC). On tap it reads the NTAG424 Type-4 NDEF file via ISO7816 APDUs (select NDEF app D2760000850101 → select file → ReadBinary NLEN + message) and extracts the lnurlw voucher (fresh SUN p/c per tap), forwarding it to the renderer on `nfc:card-tapped` (+ `nfc:status`). Lazy, guarded import — a missing reader/pcscd just reports 'unavailable', never breaking the cash-out QR path. Preload removeAllListeners guards against a double payment-trigger on renderer reload. - electron/nfc-service.ts: startNfcReader() + readNdefLnurlw()/extractLnurlw(). - electron/nfc-service.test.ts: 7 tests (NDEF URI extraction, Type-4 read sequence incl. AID select, empty-file + select-fail handling). - main.ts start + IPC forward; preload + electron.d.ts listeners. - add nfc-pcsc dep (native @pokusew/pcsclite; nix build handling next). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
74c420fbd3
commit
84d746a0da
7 changed files with 281 additions and 1 deletions
|
|
@ -195,6 +195,20 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
|||
ipcRenderer.on('hal:error', (_event, error) => callback(error))
|
||||
},
|
||||
|
||||
// Bolt Card reader (main process → renderer). removeAllListeners first: a
|
||||
// renderer reload re-runs this, and a duplicated card-tap listener would
|
||||
// trigger the LNURL-withdraw twice.
|
||||
onNfcCardTapped: (callback: (lnurlw: string) => void) => {
|
||||
ipcRenderer.removeAllListeners('nfc:card-tapped')
|
||||
ipcRenderer.on('nfc:card-tapped', (_event, lnurlw) => callback(lnurlw))
|
||||
},
|
||||
onNfcStatus: (
|
||||
callback: (status: { state: string; reader?: string; message?: string }) => void
|
||||
) => {
|
||||
ipcRenderer.removeAllListeners('nfc:status')
|
||||
ipcRenderer.on('nfc:status', (_event, status) => callback(status))
|
||||
},
|
||||
|
||||
// Watchdog heartbeat (main process → renderer → main process)
|
||||
onWatchdogPing: (callback: () => void) => {
|
||||
ipcRenderer.on('watchdog:ping', () => callback())
|
||||
|
|
@ -295,6 +309,10 @@ declare global {
|
|||
onHalBillInserted: (callback: (denomination: number) => void) => void
|
||||
onHalBillRejected: (callback: (reason: string) => void) => void
|
||||
onHalError: (callback: (error: string) => void) => void
|
||||
onNfcCardTapped: (callback: (lnurlw: string) => void) => void
|
||||
onNfcStatus: (
|
||||
callback: (status: { state: string; reader?: string; message?: string }) => void
|
||||
) => void
|
||||
onWatchdogPing: (callback: () => void) => void
|
||||
watchdogPong: () => Promise<void>
|
||||
platform: NodeJS.Platform
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue