fix(access): session Complete failed on IPC clone; keep rate lookup off the unlock path #97
1 changed files with 18 additions and 2 deletions
fix(access): pass plain objects over IPC for session Complete
At Complete the store handed the session's withdraw/pay step to window.electronAPI straight out of the loadedBoltCard ref — a Vue reactive proxy — and Electron's structured clone refused it: '[ATM] Bolt Card withdraw failed: Error: An object could not be cloned.' (sintra, 2026-09-21 06:51). The customer had to re-tap, which works because the direct-tap path passes a plain string. Copy the steps field by field into plain objects before they cross the bridge. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
commit
42e3657fe1
|
|
@ -306,6 +306,22 @@ export const useAtmStore = defineStore('atm', () => {
|
|||
// screen (raw lnurlw, spent by this call) or the session opened at entry
|
||||
// (hit-keyed steps, no p/c).
|
||||
type BoltCardSource = { lnurlw: string } | { session: CardSession }
|
||||
// Electron IPC structured-clones its arguments and rejects Vue reactive
|
||||
// proxies with "An object could not be cloned". `loadedBoltCard` is a ref,
|
||||
// so anything reached through it is a proxy — copy the steps field by field
|
||||
// into plain objects before they cross the bridge.
|
||||
const plainWithdrawStep = (w: NonNullable<CardSession['withdraw']>) => ({
|
||||
callback: w.callback,
|
||||
k1: w.k1,
|
||||
minWithdrawable: w.minWithdrawable,
|
||||
maxWithdrawable: w.maxWithdrawable,
|
||||
})
|
||||
const plainPayStep = (p: CardSession['pay']) => ({
|
||||
callback: p.callback,
|
||||
minSendable: p.minSendable,
|
||||
maxSendable: p.maxSendable,
|
||||
metadata: p.metadata,
|
||||
})
|
||||
// Access-control gate config (ADR-003). Defaults disabled → the machine's
|
||||
// `locked` state bypasses straight to `idle` (behaviour identical to no gate).
|
||||
// Populated from RuntimeConfig.accessControl in initializeForProduction.
|
||||
|
|
@ -673,7 +689,7 @@ export const useAtmStore = defineStore('atm', () => {
|
|||
'session' in source
|
||||
? source.session.withdraw
|
||||
? await api.withdrawWithSession({
|
||||
withdraw: source.session.withdraw,
|
||||
withdraw: plainWithdrawStep(source.session.withdraw),
|
||||
bolt11: invoice,
|
||||
amountMsat,
|
||||
})
|
||||
|
|
@ -713,7 +729,7 @@ export const useAtmStore = defineStore('atm', () => {
|
|||
const api = window.electronAPI!
|
||||
const res =
|
||||
'session' in source
|
||||
? await api.resolveSessionInvoice({ pay: source.session.pay, amountMsat })
|
||||
? await api.resolveSessionInvoice({ pay: plainPayStep(source.session.pay), amountMsat })
|
||||
: await api.resolveCardInvoice({ lnurlw: source.lnurlw, amountMsat })
|
||||
if (!res.ok || !res.bolt11) {
|
||||
boltCardProcessing.value = false
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue