Fix Cashu file redemption and Bitcoin-dependent wallet readiness

This commit is contained in:
archipelago
2026-09-29 14:42:44 -04:00
parent 540639d2c1
commit 0f85f588fb
41 changed files with 1641 additions and 214 deletions
@@ -76,6 +76,24 @@ describe('useTxExplorer.openTx', () => {
expect(openSession).toHaveBeenCalledWith('mempool', { path: `/tx/${TX}` })
})
it('does not open an external explorer while container discovery is pending', async () => {
const external = vi.spyOn(window, 'open').mockImplementation(() => null)
let finish!: () => void
ensureFetched.mockImplementationOnce(() => new Promise<void>(resolve => {
finish = () => { fetched = true; resolve() }
}))
const { openTx, setExplorer } = useTxExplorer()
setExplorer(DEFAULT_TX_EXPLORER, true)
const opening = openTx(TX)
expect(external).not.toHaveBeenCalled()
expect(openSession).not.toHaveBeenCalled()
finish()
await opening
expect(openSession).toHaveBeenCalledWith('mempool', { path: `/tx/${TX}` })
expect(external).not.toHaveBeenCalled()
external.mockRestore()
})
it('asks for consent only when Mempool genuinely is not installed', async () => {
containerState = 'not-installed'
const { openTx, pendingTx } = useTxExplorer()
@@ -84,3 +102,23 @@ describe('useTxExplorer.openTx', () => {
expect(pendingTx.value).toBe(TX)
})
})
describe('explorer default migration', () => {
beforeEach(() => { localStorage.clear(); vi.resetModules() })
it('uses mempool.space with consent for a new browser', async () => {
const { useTxExplorer } = await import('../useTxExplorer')
expect(useTxExplorer().prefs.value).toEqual({ url: 'https://mempool.space', acknowledged: false })
})
it.each(['https://tx1138.com', 'https://tx1138.com/', 'http://tx1138.com'])('migrates %s and resets consent', async url => {
localStorage.setItem('archipelago.tx-explorer.v1', JSON.stringify({ url, acknowledged: true }))
const { useTxExplorer } = await import('../useTxExplorer')
expect(useTxExplorer().prefs.value).toEqual({ url: 'https://mempool.space', acknowledged: false })
expect(JSON.parse(localStorage.getItem('archipelago.tx-explorer.v1')!)).toEqual(useTxExplorer().prefs.value)
})
it('preserves a custom explorer and its consent', async () => {
const prefs = { url: 'https://my-explorer.example', acknowledged: true }
localStorage.setItem('archipelago.tx-explorer.v1', JSON.stringify(prefs))
const { useTxExplorer } = await import('../useTxExplorer')
expect(useTxExplorer().prefs.value).toEqual(prefs)
})
})
+9 -3
View File
@@ -17,8 +17,8 @@ import { ref } from 'vue'
import { useAppLauncherStore } from '@/stores/appLauncher'
import { useContainerStore } from '@/stores/container'
export const DEFAULT_TX_EXPLORER = 'https://tx1138.com'
export const EXPLORER_PLACEHOLDER = 'https://mempool.guide'
export const DEFAULT_TX_EXPLORER = 'https://mempool.space'
export const EXPLORER_PLACEHOLDER = DEFAULT_TX_EXPLORER
const KEY = 'archipelago.tx-explorer.v1'
@@ -30,7 +30,13 @@ interface TxExplorerPrefs {
function loadPrefs(): TxExplorerPrefs {
const defaults: TxExplorerPrefs = { url: DEFAULT_TX_EXPLORER, acknowledged: false }
try {
return { ...defaults, ...JSON.parse(localStorage.getItem(KEY) || '{}') }
const stored = { ...defaults, ...JSON.parse(localStorage.getItem(KEY) || '{}') }
// Changing operators requires fresh consent, even if the old one was trusted.
if (typeof stored.url === 'string' && /^https?:\/\/tx1138\.com\/*$/i.test(stored.url.trim())) {
localStorage.setItem(KEY, JSON.stringify(defaults))
return defaults
}
return stored
} catch {
return defaults
}