You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
94 lines
3.0 KiB
94 lines
3.0 KiB
/** |
|
* Kind 0 JSON payment hints (incl. Garnet {@code cryptocurrency_addresses}) → payto methods. |
|
*/ |
|
|
|
import paytoTypesCatalog from '@/data/payto-types.json' |
|
import { buildPaytoUri } from '@/lib/payto' |
|
import { extractAboutCoinPaymentMethods } from '@/lib/payto-about-coin-lines' |
|
import { getCanonicalPaytoType, getPaytoEditorTypeLabel, isKnownPaytoType } from '@/lib/payto-registry' |
|
|
|
export type Kind0ImportedPaymentMethod = { |
|
type: string |
|
authority: string |
|
payto: string |
|
displayType: string |
|
} |
|
|
|
type PaytoKind0ImportCatalog = { |
|
kind0CryptocurrencyAddresses?: Record<string, string> |
|
kind0RootPaymentFields?: Record<string, string> |
|
} |
|
|
|
const importCatalog = paytoTypesCatalog as PaytoKind0ImportCatalog |
|
|
|
function mapExternalKeyToPaytoType(externalKey: string): string | null { |
|
const k = externalKey.trim().toLowerCase() |
|
if (!k) return null |
|
const fromCrypto = importCatalog.kind0CryptocurrencyAddresses?.[k] |
|
if (fromCrypto) return getCanonicalPaytoType(fromCrypto) |
|
const fromRoot = importCatalog.kind0RootPaymentFields?.[k] |
|
if (fromRoot) return getCanonicalPaytoType(fromRoot) |
|
const canonical = getCanonicalPaytoType(k) |
|
return isKnownPaytoType(canonical) ? canonical : null |
|
} |
|
|
|
function readStringAddress(value: unknown): string | null { |
|
if (typeof value !== 'string') return null |
|
const s = value.trim() |
|
return s.length > 0 ? s : null |
|
} |
|
|
|
/** |
|
* Extract payto-shaped methods from parsed kind 0 metadata JSON. |
|
* Supports Garnet `cryptocurrency_addresses` and legacy top-level coin keys. |
|
*/ |
|
export function extractKind0PaymentMethodsFromProfileJson( |
|
profileJson: unknown |
|
): Kind0ImportedPaymentMethod[] { |
|
if (!profileJson || typeof profileJson !== 'object' || Array.isArray(profileJson)) { |
|
return [] |
|
} |
|
|
|
const obj = profileJson as Record<string, unknown> |
|
const seen = new Set<string>() |
|
const out: Kind0ImportedPaymentMethod[] = [] |
|
|
|
const push = (externalKey: string, address: string) => { |
|
const paytoType = mapExternalKeyToPaytoType(externalKey) |
|
if (!paytoType) return |
|
const authority = address.trim() |
|
if (!authority) return |
|
const dedupe = `${paytoType}:${authority.toLowerCase()}` |
|
if (seen.has(dedupe)) return |
|
seen.add(dedupe) |
|
out.push({ |
|
type: paytoType, |
|
authority, |
|
payto: buildPaytoUri(paytoType, authority), |
|
displayType: getPaytoEditorTypeLabel(paytoType) |
|
}) |
|
} |
|
|
|
const cryptoBlock = obj.cryptocurrency_addresses |
|
if (cryptoBlock && typeof cryptoBlock === 'object' && !Array.isArray(cryptoBlock)) { |
|
for (const [key, value] of Object.entries(cryptoBlock as Record<string, unknown>)) { |
|
const addr = readStringAddress(value) |
|
if (addr) push(key, addr) |
|
} |
|
} |
|
|
|
const rootKeys = importCatalog.kind0RootPaymentFields ?? {} |
|
for (const externalKey of Object.keys(rootKeys)) { |
|
const addr = readStringAddress(obj[externalKey]) |
|
if (addr) push(externalKey, addr) |
|
} |
|
|
|
const about = obj.about |
|
if (typeof about === 'string' && about.trim()) { |
|
for (const m of extractAboutCoinPaymentMethods(about)) { |
|
push(m.type, m.authority) |
|
} |
|
} |
|
|
|
return out |
|
}
|
|
|