Archipelago — open-source initial import
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
export interface DetectedBitcoinAddress {
|
||||
address: string
|
||||
type: 'bech32' | 'bech32m' | 'p2pkh' | 'p2sh' | 'testnet'
|
||||
}
|
||||
|
||||
export interface DetectedLightningInvoice {
|
||||
invoice: string
|
||||
amount?: number
|
||||
description?: string
|
||||
}
|
||||
|
||||
export interface DetectedBolt12Offer {
|
||||
offer: string
|
||||
}
|
||||
|
||||
export interface DetectedTxId {
|
||||
txid: string
|
||||
}
|
||||
|
||||
// Bitcoin address patterns
|
||||
const BECH32_REGEX = /\b(bc1q[a-z0-9]{38,62})\b/gi
|
||||
const BECH32M_REGEX = /\b(bc1p[a-z0-9]{38,62})\b/gi
|
||||
const P2PKH_REGEX = /\b(1[13456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{25,34})\b/g
|
||||
const P2SH_REGEX = /\b(3[13456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{25,34})\b/g
|
||||
const TESTNET_REGEX = /\b(tb1[a-z0-9]{38,62})\b/gi
|
||||
|
||||
// Lightning patterns
|
||||
const BOLT11_REGEX = /\b(lnbc[a-z0-9]+)\b/gi
|
||||
const BOLT12_REGEX = /\b(lno1[a-z0-9]+)\b/gi
|
||||
|
||||
// Transaction ID (64 hex chars)
|
||||
const TXID_REGEX = /\b([a-f0-9]{64})\b/gi
|
||||
|
||||
export function detectBitcoinAddresses(text: string): DetectedBitcoinAddress[] {
|
||||
const addresses: DetectedBitcoinAddress[] = []
|
||||
const seen = new Set<string>()
|
||||
|
||||
for (const match of text.matchAll(BECH32_REGEX)) {
|
||||
if (!seen.has(match[1].toLowerCase())) {
|
||||
seen.add(match[1].toLowerCase())
|
||||
addresses.push({ address: match[1], type: 'bech32' })
|
||||
}
|
||||
}
|
||||
for (const match of text.matchAll(BECH32M_REGEX)) {
|
||||
if (!seen.has(match[1].toLowerCase())) {
|
||||
seen.add(match[1].toLowerCase())
|
||||
addresses.push({ address: match[1], type: 'bech32m' })
|
||||
}
|
||||
}
|
||||
for (const match of text.matchAll(P2PKH_REGEX)) {
|
||||
if (!seen.has(match[1])) {
|
||||
seen.add(match[1])
|
||||
addresses.push({ address: match[1], type: 'p2pkh' })
|
||||
}
|
||||
}
|
||||
for (const match of text.matchAll(P2SH_REGEX)) {
|
||||
if (!seen.has(match[1])) {
|
||||
seen.add(match[1])
|
||||
addresses.push({ address: match[1], type: 'p2sh' })
|
||||
}
|
||||
}
|
||||
for (const match of text.matchAll(TESTNET_REGEX)) {
|
||||
if (!seen.has(match[1].toLowerCase())) {
|
||||
seen.add(match[1].toLowerCase())
|
||||
addresses.push({ address: match[1], type: 'testnet' })
|
||||
}
|
||||
}
|
||||
|
||||
return addresses
|
||||
}
|
||||
|
||||
export function detectBolt11Invoices(text: string): DetectedLightningInvoice[] {
|
||||
const invoices: DetectedLightningInvoice[] = []
|
||||
const seen = new Set<string>()
|
||||
|
||||
for (const match of text.matchAll(BOLT11_REGEX)) {
|
||||
const lower = match[1].toLowerCase()
|
||||
if (!seen.has(lower)) {
|
||||
seen.add(lower)
|
||||
invoices.push({ invoice: match[1] })
|
||||
}
|
||||
}
|
||||
|
||||
return invoices
|
||||
}
|
||||
|
||||
export function detectBolt12Offers(text: string): DetectedBolt12Offer[] {
|
||||
const offers: DetectedBolt12Offer[] = []
|
||||
const seen = new Set<string>()
|
||||
|
||||
for (const match of text.matchAll(BOLT12_REGEX)) {
|
||||
const lower = match[1].toLowerCase()
|
||||
if (!seen.has(lower)) {
|
||||
seen.add(lower)
|
||||
offers.push({ offer: match[1] })
|
||||
}
|
||||
}
|
||||
|
||||
return offers
|
||||
}
|
||||
|
||||
export function detectTxIds(text: string): DetectedTxId[] {
|
||||
const txids: DetectedTxId[] = []
|
||||
const seen = new Set<string>()
|
||||
|
||||
for (const match of text.matchAll(TXID_REGEX)) {
|
||||
if (!seen.has(match[1])) {
|
||||
seen.add(match[1])
|
||||
txids.push({ txid: match[1] })
|
||||
}
|
||||
}
|
||||
|
||||
return txids
|
||||
}
|
||||
Reference in New Issue
Block a user