Compare commits

...

2 commits

Author SHA1 Message Date
8438e9f26d Merge pull request 'fix(wallet): narrow the bolt11 amount section so the build passes' (#168) from fix/wallet-bolt11-section-narrowing into dev
Reviewed-on: #168
2026-09-22 21:15:59 +00:00
f444677872 fix(wallet): narrow the bolt11 amount section so the build passes
`dev` does not build. This is fallout from #162: `vue-tsc -b` rejects
`section.value` with

    error TS2339: Property 'value' does not exist on type 'Section'.
      Property 'value' does not exist on type '{ name: "checksum"; letters: string; }'.

`Section` is a discriminated union and its "checksum" member carries
only `letters`. The predicate was written as `(s: any) => ...`, which is
not a type guard, so `find` returned the whole union and `.value` could
not resolve against every member.

Replaced with a real type predicate narrowing to the `amount` member.

My fault for how I verified #162: I ran `vue-tsc --noEmit`, but the
build script runs `vue-tsc -b`, which uses the project-reference config
and is stricter. The two disagree, so `--noEmit` alone is not evidence
that the build passes. #166 did run a full build, but it was branched
off #165 and so never contained this code.

Amountless behaviour is unchanged, re-verified after the narrowing:
  amountless BOLT11 -> 0        (amount_msat sent)
  live 777-sat       -> 777000  (amount_msat omitted)
  malformed          -> null    (defer to server)

`npm run build:wallet` now succeeds.
2026-09-22 23:09:34 +02:00

View file

@ -4,6 +4,9 @@ import { injectService, SERVICE_TOKENS } from '@/core/di-container'
import { config } from '@/lib/config'
import { decode as decodeBolt11 } from 'light-bolt11-decoder'
/** The `amount` member of light-bolt11-decoder's `Section` union. */
type AmountSection = { name: 'amount'; letters: string; value: string }
export interface PayLink {
id: string
wallet: string
@ -344,7 +347,14 @@ export default class WalletService extends BaseService {
private getInvoiceAmountMsat(bolt11: string): number | null {
try {
const decoded = decodeBolt11(bolt11)
const section = decoded.sections.find((s: any) => s.name === 'amount')
// `sections` is a discriminated union, and not every member carries a
// `value` — the "checksum" member has only `letters`. Narrow with a
// type predicate so the compiler knows which member we are reading;
// an `(s: any)` callback is not a type guard, so `find` still returned
// the whole union and `.value` failed to resolve under `vue-tsc -b`.
const section = decoded.sections.find(
(s): s is AmountSection => s.name === 'amount'
)
if (!section || section.value === undefined || section.value === null) return 0
return Number(section.value)
} catch (error) {