{"version":3,"sources":["../src/qr-parsers/index.ts","../src/qr-parsers/errors.ts","../src/country/currency.ts","../src/country/currencies/ars.ts","../src/country/types.ts","../src/country/qr-validator.ts","../src/country/currencies/bob.ts","../src/country/currencies/brl.ts","../src/country/currencies/cop.ts","../src/country/currencies/cup.ts","../src/country/currencies/ecu.ts","../src/country/currencies/eur.ts","../src/country/currencies/idr.ts","../src/country/currencies/inr.ts","../src/country/currencies/mex.ts","../src/country/currencies/ngn.ts","../src/country/currencies/pen.ts","../src/country/currencies/php.ts","../src/country/currencies/usd.ts","../src/country/currencies/ven.ts","../src/country/countries.ts","../src/qr-parsers/types.ts","../src/qr-parsers/utils/crc16.ts","../src/qr-parsers/utils/tlv.ts","../src/qr-parsers/parsers/ars.ts","../src/qr-parsers/utils/amount.ts","../src/qr-parsers/parsers/bob.ts","../src/qr-parsers/parsers/brl.ts","../src/qr-parsers/parsers/cop.ts","../src/qr-parsers/parsers/cup.ts","../src/qr-parsers/parsers/ecu.ts","../src/qr-parsers/parsers/idr.ts","../src/qr-parsers/parsers/inr.ts","../src/qr-parsers/parsers/ngn.ts","../src/qr-parsers/parsers/pen.ts","../src/qr-parsers/parsers/php.ts","../src/qr-parsers/parsers/ven.ts","../src/qr-parsers/parse-qr.ts"],"sourcesContent":["export { QRParserError, type QRParserErrorCode } from \"./errors\";\nexport { parseQR } from \"./parse-qr\";\nexport { isPagoMovilQr } from \"./parsers/ven\";\nexport type {\n\tParsedQR,\n\tParseQRParams,\n\tParseResult,\n\tSupportedCurrency,\n} from \"./types\";\n","export type QRParserErrorCode =\n\t| \"INVALID_QR\"\n\t| \"INVALID_CURRENCY\"\n\t| \"INVALID_AMOUNT\"\n\t| \"FETCH_FAILED\";\n\nexport class QRParserError extends Error {\n\treadonly code: QRParserErrorCode;\n\treadonly cause?: unknown;\n\treadonly context?: Record<string, unknown>;\n\n\tconstructor(\n\t\tmessage: string,\n\t\toptions: {\n\t\t\tcode: QRParserErrorCode;\n\t\t\tcause?: unknown;\n\t\t\tcontext?: Record<string, unknown>;\n\t\t},\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"QRParserError\";\n\t\tthis.code = options.code;\n\t\tthis.cause = options.cause;\n\t\tthis.context = options.context;\n\t}\n}\n","/**\n * All supported currency symbols. Single source of truth for the SDK.\n *\n * Lives alongside the country metadata so that adding a currency is a\n * single-folder operation: drop a new file in `currencies/<code>.ts`, add it\n * to this map, and both `COUNTRY_OPTIONS` and `ZodCurrencySchema` pick it up.\n */\nexport const CURRENCY = {\n\tIDR: \"IDR\",\n\tINR: \"INR\",\n\tBRL: \"BRL\",\n\tARS: \"ARS\",\n\tMEX: \"MEX\",\n\tVEN: \"VEN\",\n\tBOB: \"BOB\",\n\tEUR: \"EUR\",\n\tNGN: \"NGN\",\n\tUSD: \"USD\",\n\tCOP: \"COP\",\n\tCUP: \"CUP\",\n\tECU: \"ECU\",\n\tPEN: \"PEN\",\n\tPHP: \"PHP\",\n} as const;\n\n/** Union of supported currency codes. */\nexport type CurrencyCode = (typeof CURRENCY)[keyof typeof CURRENCY];\n\n/**\n * Tuple form of the currency codes — used by `z.enum(...)` in the shared\n * validation layer. Narrow tuple type required by Zod.\n */\nexport const CURRENCY_CODES = Object.values(CURRENCY) as [CurrencyCode, ...CurrencyCode[]];\n","import { CURRENCY } from \"../currency\";\nimport type { CountryOption, PaymentIdFieldConfig } from \"../types\";\n\nexport const ARS_PLACEHOLDER = \"juan.perez\";\nexport const ARS_VALIDATION_ERROR =\n\t\"Please enter a valid CBU/CVU (22 digits) or Alias (6-20 characters)\";\n\n/** Validates CBU (Clave Bancaria Uniforme) — Argentine banking key, 22 digits with checksums. */\nfunction validateCBU(cbu: string): boolean {\n\tif (cbu.length !== 22) return false;\n\tif (/^(\\d)\\1{21}$/.test(cbu)) return false;\n\n\tconst bankCode = cbu.substring(0, 7);\n\tconst bankCheckDigit = parseInt(cbu[7], 10);\n\tlet sum = 0;\n\tconst weights = [7, 1, 3, 9, 7, 1, 3];\n\tfor (let i = 0; i < 7; i++) {\n\t\tsum += parseInt(bankCode[i], 10) * weights[i];\n\t}\n\tconst calculatedBankCheck = (10 - (sum % 10)) % 10;\n\tif (bankCheckDigit !== calculatedBankCheck) return false;\n\n\tconst accountNumber = cbu.substring(8, 21);\n\tconst accountCheckDigit = parseInt(cbu[21], 10);\n\tsum = 0;\n\tconst accountWeights = [3, 9, 7, 1, 3, 9, 7, 1, 3, 9, 7, 1, 3];\n\tfor (let i = 0; i < 13; i++) {\n\t\tsum += parseInt(accountNumber[i], 10) * accountWeights[i];\n\t}\n\tconst calculatedAccountCheck = (10 - (sum % 10)) % 10;\n\tif (accountCheckDigit !== calculatedAccountCheck) return false;\n\n\treturn true;\n}\n\n/**\n * Validates Argentine payment IDs (CBU, CVU, or Alias).\n * CBU/CVU: 22 digits with checksum. Alias: 6-20 alphanumeric characters.\n */\nexport function validateArgentinePaymentId(paymentId: string): boolean {\n\tif (!paymentId || paymentId.trim().length === 0) return false;\n\n\tconst trimmedPaymentId = paymentId.trim();\n\n\tif (/^\\d{22}$/.test(trimmedPaymentId)) return validateCBU(trimmedPaymentId);\n\tif (/^[a-zA-Z0-9.\\-_]{6,20}$/.test(trimmedPaymentId)) return true;\n\n\treturn false;\n}\n\n/** Payment ID field configuration for ARS (Argentina, ALIAS). */\nexport const ARS_PAYMENT_FIELDS: PaymentIdFieldConfig[] = [\n\t{\n\t\tkey: \"alias\",\n\t\tlabel: \"ALIAS_ID\",\n\t\tplaceholder: ARS_PLACEHOLDER,\n\t\tdisplayLabel: \"Alias\",\n\t\tvalidate: validateArgentinePaymentId,\n\t\tvalidationErrorMessage: ARS_VALIDATION_ERROR,\n\t},\n];\n\n/** Country option for Argentina (ARS). */\nexport const ARS_COUNTRY_OPTION: CountryOption = {\n\tcountry: \"Argentina\",\n\tcurrency: CURRENCY.ARS,\n\tsymbolNative: \"$\",\n\tlocale: \"es-AR\",\n\tpaymentMethod: \"ALIAS\",\n\tpaymentAddressName: \"ALIAS_ID\",\n\ttimezone: \"America/Argentina/Buenos_Aires\",\n\ttimezone_name: \"ART\",\n\tflag: \"🇦🇷\",\n\tflagUrl: \"https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/72x72/1f1e6-1f1f7.png\",\n\tphoneCode: \"+54\",\n\ttelegramSupportChannel: \"https://t.me/p2pmeargentina\",\n\ttwitterUsername: \"p2pmeargentina\",\n\tsmsCountryCodes: [\"AR\"],\n\tprecision: 2,\n\tisAlpha: false,\n\tdisabled: false,\n\tdisabledPaymentTypes: [],\n};\n","import type { CurrencyCode } from \"../types\";\n\n/** Joins an optional QR payload with typed fields (`qr||phone|cci`). */\nexport const PACKED_PAYMENT_ID_SEP = \"||\";\n\nexport interface PaymentIdFieldConfig {\n\treadonly key: string;\n\treadonly label: string;\n\treadonly placeholder: string;\n\treadonly displayLabel: string | null;\n\treadonly validate: (value: string) => boolean;\n\treadonly validationErrorMessage: string;\n\t/**\n\t * When true, an empty value is allowed. If every field is optional, at least\n\t * one field must still be filled (see `validatePaymentIdFields`).\n\t */\n\treadonly optional?: boolean;\n}\n\nexport interface CountryOption {\n\treadonly country: string;\n\treadonly currency: CurrencyCode;\n\treadonly internationalFormat?: string;\n\treadonly symbolNative: string;\n\treadonly locale: string;\n\treadonly paymentMethod: string;\n\treadonly paymentAddressName: string;\n\treadonly timezone: string;\n\treadonly timezone_name: string;\n\treadonly flag: string;\n\treadonly phoneCode?: string;\n\treadonly flagUrl: string;\n\treadonly telegramSupportChannel: string;\n\treadonly twitterUsername: string;\n\treadonly smsCountryCodes: readonly string[];\n\treadonly precision: number;\n\treadonly isAlpha: boolean;\n\treadonly disabled: boolean;\n\treadonly disabledPaymentTypes: readonly string[];\n\t/**\n\t * Merchant/seller provides payment details by uploading a QR image.\n\t * Distinct from PAY, where the buyer scans a QR. Default: false.\n\t */\n\treadonly uploadPaymentQR?: boolean;\n\t/** Structural check for a standalone QR payload (no `||` pack). */\n\treadonly validateQr?: (payload: string) => boolean;\n\t/**\n\t * PAY display: payload to re-draw a stored QR. May be looser than\n\t * `validateQr` so old orders still render (e.g. Yape/Plin without CRC,\n\t * Pago Móvil without `merchantId`). Scan & Pay uses `validateQr` /\n\t * parsers, not this hook. Apps call `getPayQrPayload(currency, id)` —\n\t * do not branch on currency.\n\t */\n\treadonly getPayQrPayload?: (paymentId: string) => string | null;\n\t/**\n\t * Fill catalog fields from a validated QR (e.g. Yape/Plin phone in EMVCo).\n\t * Only used when the typed fallback did not already set the key.\n\t */\n\treadonly hydrateFieldsFromQr?: (qr: string) => Partial<Record<string, string>>;\n\t/**\n\t * i18n key for a warning shown before the payer sends fiat (e.g. a bank\n\t * outage). Apps call `getTransferWarning(currency)` — do not branch on\n\t * currency. Omit when there is no warning.\n\t */\n\treadonly transferWarning?: string;\n}\n","/**\n * QR payload checks for **SELL collection** (seller/merchant uploads a QR).\n *\n * Why this file exists: user-app and merchant-app share the same “is this\n * blob a payment QR we can store?” rules. Keeping them here means the apps\n * call `CountryOption.validateQr` instead of copying peru/ven parsers.\n *\n * This is not `@p2pdotme/sdk/qr-parsers`. Parsers are Scan & Pay: they\n * pull amount/address out of a live scan. Peru Scan & Pay (`parsePeru`)\n * reuses `validatePeruvianQr` so a bad CRC cannot become the stored ID.\n *\n * Image → string stays in the apps (`qr-scanner` needs a File / canvas).\n * This module only sees the decoded payload string.\n */\nimport { PACKED_PAYMENT_ID_SEP } from \"./types\";\n\nfunction crc16ccitt(s: string): string {\n\tlet crc = 0xffff;\n\tfor (let i = 0; i < s.length; i++) {\n\t\tcrc ^= s.charCodeAt(i) << 8;\n\t\tfor (let j = 0; j < 8; j++) {\n\t\t\tcrc = crc & 0x8000 ? (crc << 1) ^ 0x1021 : crc << 1;\n\t\t\tcrc &= 0xffff;\n\t\t}\n\t}\n\treturn crc.toString(16).toUpperCase().padStart(4, \"0\");\n}\n\n/**\n * Structural EMVCo upload check: parseable TLV, country tag 58, currency tag 53,\n * and a matching CRC-16/CCITT-FALSE (tag 63). CRC is required on upload so we\n * never persist a truncated screenshot. `getPayQrPayload` may still re-draw a\n * stored blob whose CRC later fails.\n */\nfunction validateEmvcoQr(payload: string, country: string, currency: string): boolean {\n\tif (!payload || payload.trim().length === 0) return false;\n\tconst data = payload.trim();\n\n\tconst tags: Record<string, string> = {};\n\tlet pos = 0;\n\twhile (pos + 4 <= data.length) {\n\t\tconst tag = data.substring(pos, pos + 2);\n\t\tconst lengthStr = data.substring(pos + 2, pos + 4);\n\t\tif (!/^[0-9]{2}$/.test(tag) || !/^[0-9]{2}$/.test(lengthStr)) break;\n\t\tconst length = Number.parseInt(lengthStr, 10);\n\t\tif (pos + 4 + length > data.length) break;\n\t\ttags[tag] = data.substring(pos + 4, pos + 4 + length);\n\t\tpos += 4 + length;\n\t}\n\n\tif (tags[\"58\"] !== country) return false;\n\tif (tags[\"53\"] !== currency) return false;\n\n\tconst crcTag = tags[\"63\"];\n\tif (!crcTag) return false;\n\n\tconst marker = data.lastIndexOf(\"6304\");\n\tif (marker === -1) return false;\n\n\tconst expected = crc16ccitt(data.substring(0, marker + 4));\n\treturn expected.toUpperCase() === crcTag.toUpperCase();\n}\n\n/**\n * Yape/Plin EMVCo: country PE, currency 604, CRC-16/CCITT-FALSE.\n * Same rule for SELL upload and Scan & Pay (`parsePeru`).\n * `getPayQrPayload` may still re-draw a stored blob whose CRC later fails.\n */\nexport function validatePeruvianQr(payload: string): boolean {\n\treturn validateEmvcoQr(payload, \"PE\", \"604\");\n}\n\n/**\n * Bolivia QR Simple encrypted envelope (Yape Bs, BancoSol, Banco Fie dynamic QR,\n * etc.): `<base64 ciphertext>|<hex checksum>`. The payload is bank-encrypted so we\n * cannot read account/amount — we only validate the envelope shape and store it\n * verbatim to re-render. The checksum is a hex digest whose length varies by bank\n * (24 hex for Banco Fie, 32 hex for Yape/BancoSol). Reject packed `||` IDs so a\n * stored compound string is never mistaken for a QR.\n */\nfunction isBolivianEncryptedQr(payload: string): boolean {\n\tconst trimmed = payload.trim();\n\tif (trimmed.includes(PACKED_PAYMENT_ID_SEP)) return false;\n\tconst sep = trimmed.lastIndexOf(\"|\");\n\tif (sep < 40) return false;\n\tconst blob = trimmed.slice(0, sep);\n\tconst tag = trimmed.slice(sep + 1);\n\tif (blob.length % 4 !== 0) return false;\n\tif (!/^[A-Za-z0-9+/]+={0,2}$/.test(blob)) return false;\n\treturn /^(?:[0-9A-Fa-f]{24}|[0-9A-Fa-f]{32})$/.test(tag);\n}\n\n/**\n * Bolivia QR Simple. Accepts either the encrypted envelope (Yape Bs, BancoSol\n * dynamic QR — `<base64>|<32-hex>`) or an EMVCo static QR (country BO, currency\n * 068, CRC-16/CCITT-FALSE). CRC / envelope shape is required on upload so we\n * never persist a truncated screenshot.\n */\nexport function validateBolivianQr(payload: string): boolean {\n\tif (!payload || payload.trim().length === 0) return false;\n\treturn isBolivianEncryptedQr(payload) || validateEmvcoQr(payload, \"BO\", \"068\");\n}\n\n/**\n * Suiche 7B / Pago Móvil collection QR: `base64?merchantId=NNNN&…`.\n * The base64 is bank AES — we cannot decode phone/RIF from it, only the\n * envelope. Reject packed `||` IDs so a stored compound string is never\n * treated as a QR. Same rule for SELL upload and Scan & Pay (`parsePagoMovil`).\n * `getPayQrPayload` may still re-draw a stored blob without `merchantId`.\n */\nexport function validateVenezuelanQr(payload: string): boolean {\n\tif (!payload || typeof payload !== \"string\") return false;\n\tconst trimmed = payload.trim();\n\tif (trimmed.includes(PACKED_PAYMENT_ID_SEP)) return false;\n\tconst qIdx = trimmed.indexOf(\"?\");\n\tif (qIdx < 40) return false;\n\tconst blob = trimmed.substring(0, qIdx);\n\tif (!/^[A-Za-z0-9+/=]+$/.test(blob)) return false;\n\treturn /(?:^|[?&])merchantId=\\d{3,4}(?:&|$)/.test(trimmed.substring(qIdx));\n}\n\n/** Left side of `qr||fields`, or the whole string when not packed. */\nexport function payQrCandidate(paymentId: string): string {\n\tconst trimmed = paymentId.trim();\n\tconst sep = trimmed.indexOf(PACKED_PAYMENT_ID_SEP);\n\treturn (sep >= 0 ? trimmed.slice(0, sep) : trimmed).trim();\n}\n\n/**\n * PAY display: Yape/Plin EMVCo (PE / 604) even when CRC fails.\n * SELL upload still uses `validatePeruvianQr`.\n */\nexport function isPeruvianPayQr(payload: string): boolean {\n\tif (!payload.startsWith(\"0002\")) return false;\n\treturn payload.includes(\"5802PE\") && payload.includes(\"5303604\");\n}\n\n/**\n * PAY display: Pago Móvil envelope `base64?…` without requiring merchantId.\n * SELL upload still uses `validateVenezuelanQr`.\n */\nexport function isVenezuelanPayQr(payload: string): boolean {\n\tif (!payload || payload.includes(PACKED_PAYMENT_ID_SEP)) return false;\n\tconst qIdx = payload.indexOf(\"?\");\n\tif (qIdx === -1) return false;\n\tconst blob = payload.slice(0, qIdx);\n\treturn blob.length > 0 && /^[A-Za-z0-9+/=]+$/.test(blob);\n}\n\n/**\n * PAY display: QR Ph EMVCo (PH / 608). SELL PHP is `phone|bank-name`, not a QR.\n * CRC is not required here — Scan & Pay already gated it on create.\n */\nexport function isPhilippinePayQr(payload: string): boolean {\n\tif (!payload.startsWith(\"0002\")) return false;\n\treturn payload.includes(\"5802PH\") && payload.includes(\"5303608\");\n}\n\n/**\n * PAY display: Bolivia QR Simple. EMVCo (BO / 068) even when CRC fails, or an\n * encrypted envelope `<base64>|<hex>` with a looser checksum than SELL upload\n * (16–64 hex vs 24/32). SELL still uses `validateBolivianQr`.\n */\nexport function isBolivianPayQr(payload: string): boolean {\n\tif (!payload || payload.includes(PACKED_PAYMENT_ID_SEP)) return false;\n\tif (payload.startsWith(\"0002\") && payload.includes(\"5802BO\") && payload.includes(\"5303068\")) {\n\t\treturn true;\n\t}\n\tconst sep = payload.lastIndexOf(\"|\");\n\tif (sep < 40) return false;\n\tconst blob = payload.slice(0, sep);\n\tconst tag = payload.slice(sep + 1);\n\tif (blob.length % 4 !== 0) return false;\n\tif (!/^[A-Za-z0-9+/]+={0,2}$/.test(blob)) return false;\n\treturn /^[0-9A-Fa-f]{16,64}$/.test(tag);\n}\n","import { CURRENCY } from \"../currency\";\nimport { isBolivianPayQr, payQrCandidate, validateBolivianQr } from \"../qr-validator\";\nimport type { CountryOption, PaymentIdFieldConfig } from \"../types\";\n\nexport { validateBolivianQr };\n\nexport const BOB_PLACEHOLDER = \"Bank account number (8–20 digits)\";\nexport const BOB_VALIDATION_ERROR = \"Please enter a valid Bolivian bank account number\";\n\n/**\n * Validates a Bolivian bank account number for QR Simple transfers.\n * Accepts 8–20 digits; spaces and dashes are ignored.\n */\nexport function validateBolivianAccount(account: string): boolean {\n\tif (!account || account.trim().length === 0) return false;\n\tconst cleaned = account.trim().replace(/[\\s-]/g, \"\");\n\treturn /^\\d{8,20}$/.test(cleaned);\n}\n\n/** Payment ID field configuration for BOB (Bolivia, QR Simple). */\nexport const BOB_PAYMENT_FIELDS: PaymentIdFieldConfig[] = [\n\t{\n\t\tkey: \"account\",\n\t\tlabel: \"ACCOUNT_NUMBER\",\n\t\tplaceholder: BOB_PLACEHOLDER,\n\t\tdisplayLabel: \"Cuenta\",\n\t\tvalidate: validateBolivianAccount,\n\t\tvalidationErrorMessage: BOB_VALIDATION_ERROR,\n\t},\n];\n\n/** Country option for Bolivia (BOB). */\nexport const BOB_COUNTRY_OPTION: CountryOption = {\n\tcountry: \"Bolivia\",\n\tcurrency: CURRENCY.BOB,\n\tinternationalFormat: \"BOB\",\n\tsymbolNative: \"Bs.\",\n\tlocale: \"es-BO\",\n\tpaymentMethod: \"QR_SIMPLE\",\n\tpaymentAddressName: \"QR_SIMPLE_DETAILS\",\n\ttimezone: \"America/La_Paz\",\n\ttimezone_name: \"BOT\",\n\tflag: \"🇧🇴\",\n\tflagUrl: \"https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/72x72/1f1e7-1f1f4.png\",\n\tphoneCode: \"+591\",\n\ttelegramSupportChannel: \"https://t.me/p2pmebolivia\",\n\ttwitterUsername: \"p2pmebolivia\",\n\tsmsCountryCodes: [\"BO\"],\n\tprecision: 2,\n\tisAlpha: true,\n\tdisabled: false,\n\tdisabledPaymentTypes: [],\n\tuploadPaymentQR: true,\n\tvalidateQr: validateBolivianQr,\n\tgetPayQrPayload: (paymentId) => {\n\t\tconst candidate = payQrCandidate(paymentId);\n\t\treturn isBolivianPayQr(candidate) ? candidate : null;\n\t},\n};\n","import { CURRENCY } from \"../currency\";\nimport type { CountryOption, PaymentIdFieldConfig } from \"../types\";\n\nexport const BRL_PLACEHOLDER = \"Chave pix ou pix copia e cola\";\nexport const BRL_VALIDATION_ERROR = \"Please enter a valid PIX ID\";\n\n/** Validates CPF (Brazilian tax ID for individuals). */\nfunction validateCPF(cpf: string): boolean {\n\tif (cpf.length !== 11) return false;\n\tif (/^(\\d)\\1{10}$/.test(cpf)) return false;\n\n\tlet sum = 0;\n\tfor (let i = 0; i < 9; i++) {\n\t\tsum += parseInt(cpf[i], 10) * (10 - i);\n\t}\n\tlet remainder = sum % 11;\n\tconst firstDigit = remainder < 2 ? 0 : 11 - remainder;\n\tif (parseInt(cpf[9], 10) !== firstDigit) return false;\n\n\tsum = 0;\n\tfor (let i = 0; i < 10; i++) {\n\t\tsum += parseInt(cpf[i], 10) * (11 - i);\n\t}\n\tremainder = sum % 11;\n\tconst secondDigit = remainder < 2 ? 0 : 11 - remainder;\n\treturn parseInt(cpf[10], 10) === secondDigit;\n}\n\n/** Validates CNPJ (Brazilian tax ID for companies). */\nfunction validateCNPJ(cnpj: string): boolean {\n\tif (cnpj.length !== 14) return false;\n\tif (/^(\\d)\\1{13}$/.test(cnpj)) return false;\n\n\tlet sum = 0;\n\tconst weights1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];\n\tfor (let i = 0; i < 12; i++) {\n\t\tsum += parseInt(cnpj[i], 10) * weights1[i];\n\t}\n\tlet remainder = sum % 11;\n\tconst firstDigit = remainder < 2 ? 0 : 11 - remainder;\n\tif (parseInt(cnpj[12], 10) !== firstDigit) return false;\n\n\tsum = 0;\n\tconst weights2 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];\n\tfor (let i = 0; i < 13; i++) {\n\t\tsum += parseInt(cnpj[i], 10) * weights2[i];\n\t}\n\tremainder = sum % 11;\n\tconst secondDigit = remainder < 2 ? 0 : 11 - remainder;\n\treturn parseInt(cnpj[13], 10) === secondDigit;\n}\n\n/**\n * Validates PIX ID format.\n * PIX can be: CPF (11 digits), CNPJ (14 digits), email, phone (10–11 digits or E.164),\n * random key (UUID), or a PIX \"copia e cola\" EMV QR payload (starts with 000201).\n */\nexport function validatePIXId(pixId: string): boolean {\n\tif (!pixId || pixId.trim().length === 0) return false;\n\n\tconst trimmedPixId = pixId.trim();\n\n\t// PIX \"copia e cola\" — EMV QR code payload\n\tif (/^000201/.test(trimmedPixId)) return true;\n\n\t// 11 digits: valid CPF or Brazilian mobile phone key (DDD 11–99 + digit 9 + 8 digits)\n\tif (/^\\d{11}$/.test(trimmedPixId))\n\t\treturn validateCPF(trimmedPixId) || /^[1-9][1-9]9\\d{8}$/.test(trimmedPixId);\n\tif (/^\\d{14}$/.test(trimmedPixId)) return validateCNPJ(trimmedPixId);\n\tif (/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(trimmedPixId)) return true;\n\t// Phone key: 10–11 digits (with or without country code prefix)\n\tif (/^\\d{10,11}$/.test(trimmedPixId)) return true;\n\tif (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(trimmedPixId))\n\t\treturn true;\n\n\treturn false;\n}\n\n/** Payment ID field configuration for BRL (Brazil, PIX). */\nexport const BRL_PAYMENT_FIELDS: PaymentIdFieldConfig[] = [\n\t{\n\t\tkey: \"pix\",\n\t\tlabel: \"PIX_ID\",\n\t\tplaceholder: BRL_PLACEHOLDER,\n\t\tdisplayLabel: \"PIX ID\",\n\t\tvalidate: validatePIXId,\n\t\tvalidationErrorMessage: BRL_VALIDATION_ERROR,\n\t},\n];\n\n/** Country option for Brazil (BRL). */\nexport const BRL_COUNTRY_OPTION: CountryOption = {\n\tcountry: \"Brazil\",\n\tcurrency: CURRENCY.BRL,\n\tsymbolNative: \"R$\",\n\tlocale: \"pt-BR\",\n\tpaymentMethod: \"PIX\",\n\tpaymentAddressName: \"PIX_ID\",\n\ttimezone: \"America/Sao_Paulo\",\n\ttimezone_name: \"BRT\",\n\tflag: \"🇧🇷\",\n\tflagUrl: \"https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/72x72/1f1e7-1f1f7.png\",\n\tphoneCode: \"+55\",\n\ttelegramSupportChannel: \"https://t.me/p2pmebrasil\",\n\ttwitterUsername: \"p2pmebrasil\",\n\tsmsCountryCodes: [\"BR\"],\n\tprecision: 2,\n\tisAlpha: false,\n\tdisabled: false,\n\tdisabledPaymentTypes: [],\n};\n","import { CURRENCY } from \"../currency\";\nimport type { CountryOption, PaymentIdFieldConfig } from \"../types\";\n\nexport const COP_PLACEHOLDER = \"3001234567 / juan.perez@nequi.com.co / @alias\";\nexport const COP_VALIDATION_ERROR =\n\t\"Please enter a valid Colombian payment ID (e.g., 3001234567, email, or @alias)\";\n\n/**\n * Validates Colombian payment ID for Nequi, Daviplata, or Bre-B.\n * Accepts a 10-digit phone number starting with 3, a valid email address,\n * or a Bre-B alias starting with @ (e.g. @juanperez).\n */\nexport function validateColombianPaymentId(paymentId: string): boolean {\n\tif (!paymentId || paymentId.trim().length === 0) return false;\n\tconst trimmed = paymentId.trim();\n\tif (/^3\\d{9}$/.test(trimmed)) return true;\n\tif (/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(trimmed)) return true;\n\tif (/^@\\S+$/.test(trimmed)) return true;\n\treturn false;\n}\n\n/** Payment ID field configuration for COP (Colombia, Transferencia). */\nexport const COP_PAYMENT_FIELDS: PaymentIdFieldConfig[] = [\n\t{\n\t\tkey: \"alias\",\n\t\tlabel: \"ALIAS_TRANSFERENCIA\",\n\t\tplaceholder: COP_PLACEHOLDER,\n\t\tdisplayLabel: \"Nequi / Daviplata / Bre-B\",\n\t\tvalidate: validateColombianPaymentId,\n\t\tvalidationErrorMessage: COP_VALIDATION_ERROR,\n\t},\n];\n\n/** Country option for Colombia (COP). */\nexport const COP_COUNTRY_OPTION: CountryOption = {\n\tcountry: \"Colombia\",\n\tcurrency: CURRENCY.COP,\n\tsymbolNative: \"$\",\n\tlocale: \"es-CO\",\n\tpaymentMethod: \"TRANSFERENCIA\",\n\tpaymentAddressName: \"ALIAS_TRANSFERENCIA\",\n\ttimezone: \"America/Bogota\",\n\ttimezone_name: \"COT\",\n\tflag: \"🇨🇴\",\n\tflagUrl: \"https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/72x72/1f1e8-1f1f4.png\",\n\tphoneCode: \"+57\",\n\ttelegramSupportChannel: \"https://t.me/p2pmecolombiaclientes\",\n\ttwitterUsername: \"p2pmeColombia\",\n\tsmsCountryCodes: [\"CO\"],\n\tprecision: 2,\n\tisAlpha: true,\n\tdisabled: false,\n\tdisabledPaymentTypes: [],\n};\n","import { CURRENCY } from \"../currency\";\nimport type { CountryOption, PaymentIdFieldConfig } from \"../types\";\n\nexport const CUP_PLACEHOLDER_PHONE = \"54004417\";\nexport const CUP_PLACEHOLDER_CARD = \"9227 9598 7238 3620\";\n\nexport const CUP_VALIDATION_ERROR_PHONE =\n\t\"Please enter a valid 8-digit phone number (e.g., 54004417)\";\nexport const CUP_VALIDATION_ERROR_CARD =\n\t\"Please enter a valid 16-digit card number (e.g., 9227 9598 7238 3620)\";\n\n/**\n * Validates Cuban phone number for Transfermóvil.\n * Format: 8 digits, optionally prefixed with the +53 country code.\n */\nexport function validateCubanPhoneNumber(phoneNumber: string): boolean {\n\tif (!phoneNumber || phoneNumber.trim().length === 0) return false;\n\n\tconst cleaned = phoneNumber.trim().replace(/\\D/g, \"\");\n\n\tif (/^\\d{8}$/.test(cleaned)) return true;\n\tif (/^53\\d{8}$/.test(cleaned)) return true;\n\n\treturn false;\n}\n\n/**\n * Validates Cuban bank card number for Transfermóvil.\n * Format: 16 digits, spaces allowed (e.g., \"9227 9598 7238 3620\").\n */\nexport function validateCubanCardNumber(cardNumber: string): boolean {\n\tif (!cardNumber || cardNumber.trim().length === 0) return false;\n\tconst cleaned = cardNumber.trim().replace(/[\\s-]/g, \"\");\n\treturn /^\\d{16}$/.test(cleaned);\n}\n\n/** Payment ID field configuration for CUP (Cuba, Transfermóvil). */\nexport const CUP_PAYMENT_FIELDS: PaymentIdFieldConfig[] = [\n\t{\n\t\tkey: \"phone\",\n\t\tlabel: \"PHONE_NUMBER\",\n\t\tplaceholder: CUP_PLACEHOLDER_PHONE,\n\t\tdisplayLabel: \"Phone\",\n\t\tvalidate: validateCubanPhoneNumber,\n\t\tvalidationErrorMessage: CUP_VALIDATION_ERROR_PHONE,\n\t},\n\t{\n\t\tkey: \"card\",\n\t\tlabel: \"CARD_NUMBER\",\n\t\tplaceholder: CUP_PLACEHOLDER_CARD,\n\t\tdisplayLabel: \"Card\",\n\t\tvalidate: validateCubanCardNumber,\n\t\tvalidationErrorMessage: CUP_VALIDATION_ERROR_CARD,\n\t},\n];\n\n/** Country option for Cuba (CUP). Transfermóvil transfers, including QR payments. */\nexport const CUP_COUNTRY_OPTION: CountryOption = {\n\tcountry: \"Cuba\",\n\tcurrency: CURRENCY.CUP,\n\tsymbolNative: \"$\",\n\tlocale: \"es-CU\",\n\tpaymentMethod: \"TRANSFERMOVIL\",\n\tpaymentAddressName: \"TRANSFERMOVIL_DETAILS\",\n\ttimezone: \"America/Havana\",\n\ttimezone_name: \"CST\",\n\tflag: \"🇨🇺\",\n\tflagUrl: \"https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/72x72/1f1e8-1f1fa.png\",\n\tphoneCode: \"+53\",\n\ttelegramSupportChannel: \"https://t.me/p2pdotmecuba\",\n\ttwitterUsername: \"P2Pdotmecuba\",\n\tsmsCountryCodes: [\"CU\"],\n\tprecision: 2,\n\tisAlpha: true,\n\tdisabled: false,\n\tdisabledPaymentTypes: [],\n\ttransferWarning: \"CUP_BANDEC_WARNING\",\n};\n","import { CURRENCY } from \"../currency\";\nimport type { CountryOption, PaymentIdFieldConfig } from \"../types\";\n\n// ── Placeholders & error messages ────────────────────────────────────────────\n\nexport const ECU_PLACEHOLDER_BANK = \"Banco Pichincha\";\nexport const ECU_PLACEHOLDER_ACCOUNT_TYPE = \"Savings / Checking\";\nexport const ECU_PLACEHOLDER_ACCOUNT_NUMBER = \"2100123456\";\nexport const ECU_PLACEHOLDER_NAME = \"Juan Pérez\";\nexport const ECU_PLACEHOLDER_CEDULA = \"1710034065\";\n\nexport const ECU_BANK_VALIDATION_ERROR = \"Please enter the bank name\";\nexport const ECU_ACCOUNT_TYPE_VALIDATION_ERROR = \"Please enter the account type\";\nexport const ECU_ACCOUNT_NUMBER_VALIDATION_ERROR =\n\t\"Please enter a valid account number (4-20 digits)\";\nexport const ECU_NAME_VALIDATION_ERROR = \"Please enter the account holder name\";\nexport const ECU_CEDULA_VALIDATION_ERROR = \"Please enter a valid Ecuadorian cédula or RUC\";\n\n// ── Validators ───────────────────────────────────────────────────────────────\n\nfunction isValidCedulaCore(cedula: string): boolean {\n\tif (!/^\\d{10}$/.test(cedula)) return false;\n\tconst province = Number(cedula.slice(0, 2));\n\tif (province < 1 || province > 24) return false;\n\tif (Number(cedula[2]) >= 6) return false;\n\n\tconst coefficients = [2, 1, 2, 1, 2, 1, 2, 1, 2];\n\tlet sum = 0;\n\tfor (let i = 0; i < 9; i++) {\n\t\tlet product = Number(cedula[i]) * coefficients[i];\n\t\tif (product > 9) product -= 9;\n\t\tsum += product;\n\t}\n\tconst checkDigit = sum % 10 === 0 ? 0 : 10 - (sum % 10);\n\treturn checkDigit === Number(cedula[9]);\n}\n\n/**\n * Validates an Ecuadorian cédula (10-digit, módulo-10 checksum) or a 13-digit RUC\n * whose first 10 digits form a valid cédula. Province must be 01–24 and the third\n * digit < 6 (natural person).\n */\nexport function validateEcuadorianCedula(value: string): boolean {\n\tif (!value || value.trim().length === 0) return false;\n\tconst cleaned = value.trim().replace(/\\D/g, \"\");\n\tif (cleaned.length === 13) return isValidCedulaCore(cleaned.slice(0, 10));\n\tif (cleaned.length !== 10) return false;\n\treturn isValidCedulaCore(cleaned);\n}\n\n/** Validates an Ecuadorian bank account number — 4–20 digits after stripping separators. */\nexport function validateEcuadorianAccountNumber(value: string): boolean {\n\tif (!value || value.trim().length === 0) return false;\n\tconst cleaned = value.trim().replace(/\\D/g, \"\");\n\treturn /^\\d{4,20}$/.test(cleaned);\n}\n\n/** Validates an account holder name — non-empty, letters/spaces/apostrophe/period/hyphen only. */\nexport function validateEcuadorianAccountName(value: string): boolean {\n\tif (!value || value.trim().length === 0) return false;\n\treturn /^[A-Za-zÀ-ÿ][A-Za-zÀ-ÿ .'-]{1,}$/.test(value.trim());\n}\n\n// ── Payment fields ───────────────────────────────────────────────────────────\n\n/** Payment ID field configuration for ECU (Ecuador, bank transfer — all free text). */\nexport const ECU_PAYMENT_FIELDS: PaymentIdFieldConfig[] = [\n\t{\n\t\tkey: \"bank-name\",\n\t\tlabel: \"BANK_NAME\",\n\t\tplaceholder: ECU_PLACEHOLDER_BANK,\n\t\tdisplayLabel: \"Bank\",\n\t\tvalidate: (v: string) => v.trim().length > 0,\n\t\tvalidationErrorMessage: ECU_BANK_VALIDATION_ERROR,\n\t},\n\t{\n\t\tkey: \"account-type\",\n\t\tlabel: \"ACCOUNT_TYPE\",\n\t\tplaceholder: ECU_PLACEHOLDER_ACCOUNT_TYPE,\n\t\tdisplayLabel: \"Account Type\",\n\t\tvalidate: (v: string) => v.trim().length > 0,\n\t\tvalidationErrorMessage: ECU_ACCOUNT_TYPE_VALIDATION_ERROR,\n\t},\n\t{\n\t\tkey: \"account-number\",\n\t\tlabel: \"ACCOUNT_NUMBER\",\n\t\tplaceholder: ECU_PLACEHOLDER_ACCOUNT_NUMBER,\n\t\tdisplayLabel: \"Account Number\",\n\t\tvalidate: validateEcuadorianAccountNumber,\n\t\tvalidationErrorMessage: ECU_ACCOUNT_NUMBER_VALIDATION_ERROR,\n\t},\n\t{\n\t\tkey: \"account-name\",\n\t\tlabel: \"NAME\",\n\t\tplaceholder: ECU_PLACEHOLDER_NAME,\n\t\tdisplayLabel: \"Name\",\n\t\tvalidate: validateEcuadorianAccountName,\n\t\tvalidationErrorMessage: ECU_NAME_VALIDATION_ERROR,\n\t},\n\t{\n\t\tkey: \"cedula\",\n\t\tlabel: \"CEDULA\",\n\t\tplaceholder: ECU_PLACEHOLDER_CEDULA,\n\t\tdisplayLabel: \"Cédula\",\n\t\tvalidate: validateEcuadorianCedula,\n\t\tvalidationErrorMessage: ECU_CEDULA_VALIDATION_ERROR,\n\t},\n];\n\n// ── Country option ───────────────────────────────────────────────────────────\n\n/** Country option for Ecuador (ECU — USD-denominated, bank transfer + DeUna QR). */\nexport const ECU_COUNTRY_OPTION: CountryOption = {\n\tcountry: \"Ecuador\",\n\tcurrency: CURRENCY.ECU,\n\tinternationalFormat: \"USD\",\n\tsymbolNative: \"$\",\n\tlocale: \"es-EC\",\n\tpaymentMethod: \"TRANSFERENCIA\",\n\tpaymentAddressName: \"ECU_BANK_DETAILS\",\n\ttimezone: \"America/Guayaquil\",\n\ttimezone_name: \"ECT\",\n\tflag: \"🇪🇨\",\n\tflagUrl: \"https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/72x72/1f1ea-1f1e8.png\",\n\tphoneCode: \"+593\",\n\ttelegramSupportChannel: \"https://t.me/Ecuador_P2P\",\n\ttwitterUsername: \"P2Pdotme_Ecu\",\n\tsmsCountryCodes: [],\n\tprecision: 2,\n\tisAlpha: true,\n\tdisabled: false,\n\tdisabledPaymentTypes: [],\n};\n","import { CURRENCY } from \"../currency\";\nimport type { CountryOption, PaymentIdFieldConfig } from \"../types\";\n\nexport const EUR_PLACEHOLDER = \"@username or email\";\nexport const EUR_VALIDATION_ERROR = \"Please enter a valid Revolut ID (username, email, or phone)\";\n\n/**\n * Validates Revolut ID (username, email, or phone number).\n */\nexport function validateRevolutId(revolutId: string): boolean {\n\tif (!revolutId || revolutId.trim().length === 0) return false;\n\n\tconst trimmed = revolutId.trim();\n\n\tif (/^@?[a-zA-Z0-9._-]{3,30}$/.test(trimmed)) return true;\n\tif (/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(trimmed)) return true;\n\tif (/^\\+?\\d{7,15}$/.test(trimmed)) return true;\n\n\treturn false;\n}\n\n/** Payment ID field configuration for EUR (Revolut EUR). */\nexport const EUR_PAYMENT_FIELDS: PaymentIdFieldConfig[] = [\n\t{\n\t\tkey: \"revolut\",\n\t\tlabel: \"REVOLUT_ID\",\n\t\tplaceholder: EUR_PLACEHOLDER,\n\t\tdisplayLabel: \"Revolut ID\",\n\t\tvalidate: validateRevolutId,\n\t\tvalidationErrorMessage: EUR_VALIDATION_ERROR,\n\t},\n];\n\n/** Country option for Revolut EUR. */\nexport const EUR_COUNTRY_OPTION: CountryOption = {\n\tcountry: \"Revolut EUR\",\n\tcurrency: CURRENCY.EUR,\n\tsymbolNative: \"€\",\n\tlocale: \"de-DE\",\n\tpaymentMethod: \"REVOLUT\",\n\tpaymentAddressName: \"REVOLUT_ID\",\n\ttimezone: \"Europe/Berlin\",\n\ttimezone_name: \"CET\",\n\tflag: \"\",\n\tflagUrl: \"https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/72x72/1f310.png\",\n\tphoneCode: \"\",\n\ttelegramSupportChannel: \"https://t.me/P2Pdotme\",\n\ttwitterUsername: \"P2Pdotme\",\n\tsmsCountryCodes: [],\n\tprecision: 2,\n\tisAlpha: true,\n\tdisabled: true,\n\tdisabledPaymentTypes: [\"PAY\"],\n};\n","import { CURRENCY } from \"../currency\";\nimport type { CountryOption, PaymentIdFieldConfig } from \"../types\";\n\nexport const IDR_PLACEHOLDER = \"8123456789\";\nexport const IDR_VALIDATION_ERROR =\n\t\"Please enter a valid Indonesian phone number (e.g., 8123456789)\";\n\n/**\n * Validates Indonesian phone number.\n * Validates just the number part (9-12 digits).\n */\nexport function validateIndonesianPhoneNumber(phoneNumber: string): boolean {\n\tif (!phoneNumber || phoneNumber.trim().length === 0) return false;\n\tif (/[a-zA-Z]/.test(phoneNumber)) return false;\n\tconst cleaned = phoneNumber.replace(/\\D/g, \"\");\n\treturn /^\\d{9,12}$/.test(cleaned);\n}\n\n/** Payment ID field configuration for IDR (Indonesia, QRIS). */\nexport const IDR_PAYMENT_FIELDS: PaymentIdFieldConfig[] = [\n\t{\n\t\tkey: \"phone\",\n\t\tlabel: \"PHONE_NUMBER\",\n\t\tplaceholder: IDR_PLACEHOLDER,\n\t\tdisplayLabel: \"Phone Number\",\n\t\tvalidate: validateIndonesianPhoneNumber,\n\t\tvalidationErrorMessage: IDR_VALIDATION_ERROR,\n\t},\n];\n\n/** Country option for Indonesia (IDR). */\nexport const IDR_COUNTRY_OPTION: CountryOption = {\n\tcountry: \"Indonesia\",\n\tcurrency: CURRENCY.IDR,\n\tsymbolNative: \"Rp\",\n\tlocale: \"id-ID\",\n\tpaymentMethod: \"QRIS\",\n\tpaymentAddressName: \"PHONE_NUMBER\",\n\ttimezone: \"Asia/Jakarta\",\n\ttimezone_name: \"WIB\",\n\tflag: \"🇮🇩\",\n\tflagUrl: \"https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/72x72/1f1ee-1f1e9.png\",\n\tphoneCode: \"+62\",\n\ttelegramSupportChannel: \"https://t.me/p2pmeindonesia\",\n\ttwitterUsername: \"p2pdotmeID\",\n\tsmsCountryCodes: [],\n\tprecision: 0,\n\tisAlpha: false,\n\tdisabled: false,\n\tdisabledPaymentTypes: [],\n};\n","import { CURRENCY } from \"../currency\";\nimport type { CountryOption, PaymentIdFieldConfig } from \"../types\";\n\nexport const INR_PLACEHOLDER = \"merchant@upi\";\nexport const INR_VALIDATION_ERROR = \"Please enter a valid UPI ID (e.g., username@bankname)\";\n\n/**\n * Validates UPI ID format.\n * UPI ID format: username@bankname (e.g., john@paytm, user@ybl, 8658404239@kotak811)\n */\nexport function validateUPIId(upiId: string): boolean {\n\tif (!upiId || upiId.trim().length === 0) return false;\n\tconst upiRegex = /^[a-zA-Z0-9.\\-_]{2,256}@[a-zA-Z0-9]{2,64}$/;\n\treturn upiRegex.test(upiId.trim());\n}\n\n/** Payment ID field configuration for INR (India, UPI). */\nexport const INR_PAYMENT_FIELDS: PaymentIdFieldConfig[] = [\n\t{\n\t\tkey: \"upi\",\n\t\tlabel: \"UPI_ID\",\n\t\tplaceholder: INR_PLACEHOLDER,\n\t\tdisplayLabel: \"UPI ID\",\n\t\tvalidate: validateUPIId,\n\t\tvalidationErrorMessage: INR_VALIDATION_ERROR,\n\t},\n];\n\n/** Country option for India (INR). */\nexport const INR_COUNTRY_OPTION: CountryOption = {\n\tcountry: \"India\",\n\tcurrency: CURRENCY.INR,\n\tsymbolNative: \"₹\",\n\tlocale: \"en-IN\",\n\tpaymentMethod: \"UPI\",\n\tpaymentAddressName: \"UPI_ID\",\n\ttimezone: \"Asia/Kolkata\",\n\ttimezone_name: \"IST\",\n\tflag: \"🇮🇳\",\n\tflagUrl: \"https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/72x72/1f1ee-1f1f3.png\",\n\tphoneCode: \"+91\",\n\ttelegramSupportChannel: \"https://t.me/P2Pdotme\",\n\ttwitterUsername: \"P2Pdotme\",\n\tsmsCountryCodes: [\"IN\"],\n\tprecision: 2,\n\tisAlpha: false,\n\tdisabled: false,\n\tdisabledPaymentTypes: [],\n};\n","import { CURRENCY } from \"../currency\";\nimport type { CountryOption, PaymentIdFieldConfig } from \"../types\";\n\nexport const MEX_PLACEHOLDER = \"012345678901234567\";\nexport const MEX_VALIDATION_ERROR =\n\t\"Please enter a valid CLABE (18 digits), card number, or phone number\";\n\n/**\n * Validates Mexican payment IDs (CLABE, card number, or phone number).\n * CLABE: 18 digits. Card: 16 digits. Phone: 10 digits.\n */\nexport function validateMexicanPaymentId(paymentId: string): boolean {\n\tif (!paymentId || paymentId.trim().length === 0) return false;\n\n\tconst trimmed = paymentId.trim().replace(/\\D/g, \"\");\n\n\tif (/^\\d{18}$/.test(trimmed)) return true;\n\tif (/^\\d{16}$/.test(trimmed)) return true;\n\tif (/^\\d{10}$/.test(trimmed)) return true;\n\n\treturn false;\n}\n\n/** Payment ID field configuration for MEX (Mexico, SPEI). */\nexport const MEX_PAYMENT_FIELDS: PaymentIdFieldConfig[] = [\n\t{\n\t\tkey: \"clabe\",\n\t\tlabel: \"CLABE_ID\",\n\t\tplaceholder: MEX_PLACEHOLDER,\n\t\tdisplayLabel: \"CLABE\",\n\t\tvalidate: validateMexicanPaymentId,\n\t\tvalidationErrorMessage: MEX_VALIDATION_ERROR,\n\t},\n];\n\n/** Country option for Mexico (MEX). */\nexport const MEX_COUNTRY_OPTION: CountryOption = {\n\tcountry: \"Mexico\",\n\tcurrency: CURRENCY.MEX,\n\tinternationalFormat: \"MXN\",\n\tsymbolNative: \"Mx\",\n\tlocale: \"es-MX\",\n\tpaymentMethod: \"SPEI\",\n\tpaymentAddressName: \"CLABE_ID\",\n\ttimezone: \"America/Mexico_City\",\n\ttimezone_name: \"CST\",\n\tflag: \"🇲🇽\",\n\tflagUrl: \"https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/72x72/1f1f2-1f1fd.png\",\n\tphoneCode: \"+52\",\n\ttelegramSupportChannel: \"https://t.me/p2pdotmex\",\n\ttwitterUsername: \"p2pmemexico\",\n\tsmsCountryCodes: [\"MX\"],\n\tprecision: 2,\n\tisAlpha: true,\n\tdisabled: true,\n\tdisabledPaymentTypes: [\"PAY\"],\n};\n","import { CURRENCY } from \"../currency\";\nimport type { CountryOption, PaymentIdFieldConfig } from \"../types\";\n\nexport const NGN_PLACEHOLDER = \"0123456789\";\nexport const NGN_PLACEHOLDER_BANK = \"Bank Name\";\nexport const NGN_PLACEHOLDER_ACCOUNT_NAME = \"Account Name\";\nexport const NGN_VALIDATION_ERROR = \"Please enter a valid 10-digit account number\";\nexport const NGN_BANK_NAME_VALIDATION_ERROR = \"Please enter a valid bank name\";\nexport const NGN_ACCOUNT_NAME_VALIDATION_ERROR = \"Please enter a valid account name\";\n\n/**\n * Validates Nigerian bank account number (NUBAN format, 10 digits).\n */\nexport function validateNigerianAccountNumber(accountNumber: string): boolean {\n\tif (!accountNumber || accountNumber.trim().length === 0) return false;\n\tconst cleaned = accountNumber.trim().replace(/\\D/g, \"\");\n\treturn /^\\d{10}$/.test(cleaned);\n}\n\n/**\n * Validates a Nigerian bank account holder name (non-empty, letters/spaces/.'- only).\n */\nexport function validateNigerianAccountName(accountName: string): boolean {\n\tif (!accountName || accountName.trim().length === 0) return false;\n\treturn /^[A-Za-z][A-Za-z .'-]{1,}$/.test(accountName.trim());\n}\n\n/** Payment ID field configuration for NGN (Nigeria, NIP). */\nexport const NGN_PAYMENT_FIELDS: PaymentIdFieldConfig[] = [\n\t{\n\t\tkey: \"account\",\n\t\tlabel: \"ACCOUNT_NUMBER\",\n\t\tplaceholder: NGN_PLACEHOLDER,\n\t\tdisplayLabel: \"Account Number\",\n\t\tvalidate: validateNigerianAccountNumber,\n\t\tvalidationErrorMessage: NGN_VALIDATION_ERROR,\n\t},\n\t{\n\t\tkey: \"bank-name\",\n\t\tlabel: \"BANK_NAME\",\n\t\tplaceholder: NGN_PLACEHOLDER_BANK,\n\t\tdisplayLabel: \"Bank Name\",\n\t\tvalidate: (v: string) => v.trim().length > 0,\n\t\tvalidationErrorMessage: NGN_BANK_NAME_VALIDATION_ERROR,\n\t},\n\t{\n\t\tkey: \"account-name\",\n\t\tlabel: \"ACCOUNT_NAME\",\n\t\tplaceholder: NGN_PLACEHOLDER_ACCOUNT_NAME,\n\t\tdisplayLabel: \"Account Name\",\n\t\tvalidate: validateNigerianAccountName,\n\t\tvalidationErrorMessage: NGN_ACCOUNT_NAME_VALIDATION_ERROR,\n\t},\n];\n\n/** Country option for Nigeria (NGN). */\nexport const NGN_COUNTRY_OPTION: CountryOption = {\n\tcountry: \"Nigeria\",\n\tcurrency: CURRENCY.NGN,\n\tsymbolNative: \"₦\",\n\tlocale: \"en-NG\",\n\tpaymentMethod: \"NIP\",\n\tpaymentAddressName: \"ACCOUNT_NUMBER\",\n\ttimezone: \"Africa/Lagos\",\n\ttimezone_name: \"WAT\",\n\tflag: \"🇳🇬\",\n\tflagUrl: \"https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/72x72/1f1f3-1f1ec.png\",\n\tphoneCode: \"+234\",\n\ttelegramSupportChannel: \"https://t.me/p2pmengn\",\n\ttwitterUsername: \"p2pmeNigeria\",\n\tsmsCountryCodes: [],\n\tprecision: 2,\n\tisAlpha: true,\n\tdisabled: false,\n\tdisabledPaymentTypes: [],\n};\n","import { CURRENCY } from \"../currency\";\nimport { isPeruvianPayQr, payQrCandidate, validatePeruvianQr } from \"../qr-validator\";\nimport { type CountryOption, PACKED_PAYMENT_ID_SEP, type PaymentIdFieldConfig } from \"../types\";\n\nexport { validatePeruvianQr };\n\nexport const PEN_PLACEHOLDER = \"CCI (20 digits) or Yape/Plin phone (9XXXXXXXX)\";\nexport const PEN_PHONE_PLACEHOLDER = \"PERU_PHONE_PLACEHOLDER\";\nexport const PEN_CCI_PLACEHOLDER = \"PERU_CCI_PLACEHOLDER\";\nexport const PEN_VALIDATION_ERROR = \"Please enter a valid 20-digit CCI or Yape/Plin phone number\";\nexport const PEN_PHONE_VALIDATION_ERROR = \"Please enter a valid Yape/Plin phone (9XXXXXXXX)\";\nexport const PEN_CCI_VALIDATION_ERROR = \"Please enter a valid 20-digit CCI\";\n\n/** Validates a 20-digit Peruvian CCI (spaces ignored). */\nexport function validatePeruvianCci(value: string): boolean {\n\tif (!value || value.trim().length === 0) return false;\n\treturn /^\\d{20}$/.test(value.trim().replace(/\\s+/g, \"\"));\n}\n\n/**\n * Validates a Yape/Plin phone: `9` + 8 digits, optional `+51` / `51` prefix.\n */\nexport function validatePeruvianPhone(value: string): boolean {\n\tif (!value || value.trim().length === 0) return false;\n\tconst phone = value\n\t\t.trim()\n\t\t.replace(/\\s+/g, \"\")\n\t\t.replace(/^\\+?51/, \"\");\n\treturn /^9\\d{8}$/.test(phone);\n}\n\n/**\n * Validates a Peruvian payment key for the legacy single-field path.\n * Accepts either a 20-digit CCI or a Yape/Plin phone number.\n */\nexport function validatePeruvianPaymentKey(value: string): boolean {\n\treturn validatePeruvianCci(value) || validatePeruvianPhone(value);\n}\n\n/** Normalizes a CCI or Yape/Plin phone to the stored digit form. */\nexport function normalizePeruvianPaymentKey(value: string): string {\n\tconst trimmed = value.trim();\n\tconst cci = trimmed.replace(/\\s+/g, \"\");\n\tif (/^\\d{20}$/.test(cci)) return cci;\n\tconst phone = trimmed.replace(/\\s+/g, \"\").replace(/^\\+?51/, \"\");\n\tif (/^9\\d{8}$/.test(phone)) return phone;\n\treturn cci;\n}\n\nexport type PeruvianPaymentIdParts = {\n\tqr: string | null;\n\tphone: string | null;\n\tcci: string | null;\n};\n\nfunction looksLikeTlv(value: string): boolean {\n\tif (value.length < 5 || !/^\\d{4}/.test(value)) return false;\n\tconst len = Number.parseInt(value.slice(2, 4), 10);\n\treturn !Number.isNaN(len) && len >= 0 && 4 + len <= value.length;\n}\n\n/**\n * Phone from a TLV value. Skips hex hashes (Yape tag 39) so `998765432`\n * inside a checksum never counts. Allows `+51` / `51` glued to a 9XXXXXXXX.\n */\nfunction phoneFromTlvValue(value: string): string | null {\n\tconst trimmed = value.trim();\n\tif (!trimmed) return null;\n\tif (validatePeruvianPhone(trimmed)) return normalizePeruvianPaymentKey(trimmed);\n\tif (/^[0-9a-f]+$/i.test(trimmed) && /[a-f]/i.test(trimmed)) return null;\n\tconst match = trimmed.match(/(^|[^0-9])(\\+?51)?(9\\d{8})(?![0-9])/);\n\tif (!match) return null;\n\tconst candidate = `${match[2] ?? \"\"}${match[3]}`;\n\treturn validatePeruvianPhone(candidate) ? normalizePeruvianPaymentKey(candidate) : null;\n}\n\n/**\n * Walks EMVCo TLV (merchant-account templates, additional data, and any nested\n * TLV) and returns the first Yape/Plin phone found.\n */\nfunction extractPeruvianPhoneFromQr(payload: string): string | null {\n\tlet pos = 0;\n\twhile (pos + 4 <= payload.length) {\n\t\tconst tag = payload.slice(pos, pos + 2);\n\t\tconst len = Number.parseInt(payload.slice(pos + 2, pos + 4), 10);\n\t\tif (Number.isNaN(len) || len < 0 || pos + 4 + len > payload.length) break;\n\t\tconst value = payload.slice(pos + 4, pos + 4 + len);\n\t\tconst direct = phoneFromTlvValue(value);\n\t\tif (direct) return direct;\n\t\tif ((tag >= \"02\" && tag <= \"51\") || tag === \"62\" || tag === \"64\" || looksLikeTlv(value)) {\n\t\t\tconst nested = extractPeruvianPhoneFromQr(value);\n\t\t\tif (nested) return nested;\n\t\t}\n\t\tpos += 4 + len;\n\t}\n\tconst glued = payload.match(/\\+51\\s*9\\d{8}/);\n\tif (glued && validatePeruvianPhone(glued[0])) {\n\t\treturn normalizePeruvianPaymentKey(glued[0]);\n\t}\n\treturn null;\n}\n\nfunction parsePeruvianFallback(value: string): Pick<PeruvianPaymentIdParts, \"phone\" | \"cci\"> {\n\tconst trimmed = value.trim();\n\tif (!trimmed) return { phone: null, cci: null };\n\tconst tokens = trimmed\n\t\t.split(\"|\")\n\t\t.map((token) => token.trim())\n\t\t.filter(Boolean);\n\tlet phone: string | null = null;\n\tlet cci: string | null = null;\n\tfor (const token of tokens) {\n\t\tif (!phone && validatePeruvianPhone(token)) {\n\t\t\tphone = normalizePeruvianPaymentKey(token);\n\t\t\tcontinue;\n\t\t}\n\t\tif (!cci && validatePeruvianCci(token)) {\n\t\t\tcci = normalizePeruvianPaymentKey(token);\n\t\t}\n\t}\n\treturn { phone, cci };\n}\n\n/**\n * Splits a stored PEN payment ID into QR payload and/or typed fallback.\n * Formats: EMVCo blob, CCI, phone, `phone|cci`, or `blob||fallback`.\n */\nexport function parsePeruvianPaymentId(value: string | null | undefined): PeruvianPaymentIdParts {\n\tif (!value || typeof value !== \"string\") {\n\t\treturn { qr: null, phone: null, cci: null };\n\t}\n\tconst trimmed = value.trim();\n\tconst sep = trimmed.indexOf(PACKED_PAYMENT_ID_SEP);\n\tif (sep >= 0) {\n\t\tconst left = trimmed.slice(0, sep);\n\t\tconst right = trimmed.slice(sep + PACKED_PAYMENT_ID_SEP.length);\n\t\tconst fallback = parsePeruvianFallback(right);\n\t\tconst qr = validatePeruvianQr(left) ? left : null;\n\t\treturn {\n\t\t\tqr,\n\t\t\tphone: fallback.phone ?? (qr ? extractPeruvianPhoneFromQr(qr) : null),\n\t\t\tcci: fallback.cci,\n\t\t};\n\t}\n\tif (validatePeruvianQr(trimmed)) {\n\t\treturn {\n\t\t\tqr: trimmed,\n\t\t\tphone: extractPeruvianPhoneFromQr(trimmed),\n\t\t\tcci: null,\n\t\t};\n\t}\n\tconst fallback = parsePeruvianFallback(trimmed);\n\treturn { qr: null, phone: fallback.phone, cci: fallback.cci };\n}\n\nexport function serializePeruvianPaymentId(\n\tqr: string | null | undefined,\n\tphone: string | null | undefined,\n\tcci: string | null | undefined,\n): string {\n\tconst q = qr?.trim() && validatePeruvianQr(qr.trim()) ? qr.trim() : \"\";\n\tconst p = phone?.trim() && validatePeruvianPhone(phone) ? normalizePeruvianPaymentKey(phone) : \"\";\n\tconst c = cci?.trim() && validatePeruvianCci(cci) ? normalizePeruvianPaymentKey(cci) : \"\";\n\tconst fallback = p && c ? `${p}|${c}` : p || c;\n\tif (q && fallback) return `${q}${PACKED_PAYMENT_ID_SEP}${fallback}`;\n\treturn q || fallback;\n}\n\nfunction isValidPeruvianTypedRest(value: string): boolean {\n\tconst nonempty = value\n\t\t.split(\"|\")\n\t\t.map((token) => token.trim())\n\t\t.filter((token) => token.length > 0);\n\tif (nonempty.length === 0) return false;\n\treturn nonempty.every((token) => validatePeruvianPhone(token) || validatePeruvianCci(token));\n}\n\n/** QR payload and/or CCI and/or Yape/Plin phone. A packed rest must be valid typed fields. */\nexport function validatePeruvianPaymentId(value: string): boolean {\n\tif (!value || typeof value !== \"string\") return false;\n\tconst trimmed = value.trim();\n\tconst sep = trimmed.indexOf(PACKED_PAYMENT_ID_SEP);\n\tif (sep >= 0) {\n\t\tconst left = trimmed.slice(0, sep);\n\t\tconst right = trimmed.slice(sep + PACKED_PAYMENT_ID_SEP.length);\n\t\tconst qrOk = validatePeruvianQr(left);\n\t\tif (right.trim()) return qrOk && isValidPeruvianTypedRest(right);\n\t\treturn qrOk;\n\t}\n\tif (validatePeruvianQr(trimmed)) return true;\n\treturn isValidPeruvianTypedRest(trimmed);\n}\n\n/** Payment ID field configuration for PEN (Peru). At least one of phone / CCI. */\nexport const PEN_PAYMENT_FIELDS: PaymentIdFieldConfig[] = [\n\t{\n\t\tkey: \"phone\",\n\t\tlabel: \"PERU_PHONE_LABEL\",\n\t\tplaceholder: PEN_PHONE_PLACEHOLDER,\n\t\tdisplayLabel: \"Yape / Plin phone\",\n\t\tvalidate: validatePeruvianPhone,\n\t\tvalidationErrorMessage: PEN_PHONE_VALIDATION_ERROR,\n\t\toptional: true,\n\t},\n\t{\n\t\tkey: \"cci\",\n\t\tlabel: \"PERU_CCI_LABEL\",\n\t\tplaceholder: PEN_CCI_PLACEHOLDER,\n\t\tdisplayLabel: \"CCI\",\n\t\tvalidate: validatePeruvianCci,\n\t\tvalidationErrorMessage: PEN_CCI_VALIDATION_ERROR,\n\t\toptional: true,\n\t},\n];\n\n/** Country option for Peru (PEN). */\nexport const PEN_COUNTRY_OPTION: CountryOption = {\n\tcountry: \"Peru\",\n\tcurrency: CURRENCY.PEN,\n\tsymbolNative: \"S/\",\n\tlocale: \"es-PE\",\n\tpaymentMethod: \"YAPE_PLIN_CCI\",\n\tpaymentAddressName: \"YAPE_PLIN_CCI_DETAILS\",\n\ttimezone: \"America/Lima\",\n\ttimezone_name: \"PET\",\n\tflag: \"🇵🇪\",\n\tflagUrl: \"https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/72x72/1f1f5-1f1ea.png\",\n\tphoneCode: \"+51\",\n\ttelegramSupportChannel: \"https://t.me/p2pmeperu\",\n\ttwitterUsername: \"p2pmePeru\",\n\tsmsCountryCodes: [\"PE\"],\n\tprecision: 2,\n\tisAlpha: true,\n\tdisabled: false,\n\tdisabledPaymentTypes: [],\n\tuploadPaymentQR: true,\n\tvalidateQr: validatePeruvianQr,\n\tgetPayQrPayload: (paymentId) => {\n\t\tconst candidate = payQrCandidate(paymentId);\n\t\treturn isPeruvianPayQr(candidate) ? candidate : null;\n\t},\n\thydrateFieldsFromQr: (qr) => {\n\t\tconst phone = extractPeruvianPhoneFromQr(qr);\n\t\treturn phone ? { phone } : {};\n\t},\n};\n","import { CURRENCY } from \"../currency\";\nimport { isPhilippinePayQr, payQrCandidate } from \"../qr-validator\";\nimport type { CountryOption, PaymentIdFieldConfig } from \"../types\";\n\nexport const PHP_PLACEHOLDER_PHONE = \"9171234567\";\nexport const PHP_PLACEHOLDER_BANK = \"GCash\";\n\nexport const PHP_VALIDATION_ERROR_PHONE =\n\t\"Please enter a valid Philippine mobile number (e.g., 9171234567)\";\nexport const PHP_BANK_NAME_VALIDATION_ERROR = \"Please enter the receiving bank or e-wallet\";\n\n/**\n * Validates a Philippine mobile number for InstaPay (GCash / Maya).\n * Mobile numbers are 10 digits starting with 9, and are commonly written\n * locally as `09XXXXXXXXX` or internationally as `+63 9XXXXXXXXX`.\n */\nexport function validatePhilippinePhoneNumber(phoneNumber: string): boolean {\n\tif (!phoneNumber || phoneNumber.trim().length === 0) return false;\n\tif (/[a-zA-Z]/.test(phoneNumber)) return false;\n\n\tconst cleaned = phoneNumber.trim().replace(/\\D/g, \"\");\n\n\tif (/^9\\d{9}$/.test(cleaned)) return true;\n\tif (/^09\\d{9}$/.test(cleaned)) return true;\n\tif (/^639\\d{9}$/.test(cleaned)) return true;\n\n\treturn false;\n}\n\n/**\n * Payment ID field configuration for PHP (Philippines, InstaPay).\n *\n * InstaPay is an interbank rail, so the receiving institution has to be named\n * alongside the number — it may be an e-wallet (GCash, Maya), a digital bank\n * (GoTyme) or a local bank. For e-wallets the account number is the mobile\n * number the wallet is registered to.\n */\nexport const PHP_PAYMENT_FIELDS: PaymentIdFieldConfig[] = [\n\t{\n\t\tkey: \"phone\",\n\t\tlabel: \"PHONE_NUMBER\",\n\t\tplaceholder: PHP_PLACEHOLDER_PHONE,\n\t\tdisplayLabel: \"Phone Number\",\n\t\tvalidate: validatePhilippinePhoneNumber,\n\t\tvalidationErrorMessage: PHP_VALIDATION_ERROR_PHONE,\n\t},\n\t{\n\t\tkey: \"bank-name\",\n\t\tlabel: \"BANK_NAME\",\n\t\tplaceholder: PHP_PLACEHOLDER_BANK,\n\t\tdisplayLabel: \"Bank Name\",\n\t\tvalidate: (v: string) => v.trim().length > 0,\n\t\tvalidationErrorMessage: PHP_BANK_NAME_VALIDATION_ERROR,\n\t},\n];\n\n/**\n * Country option for the Philippines (PHP).\n *\n * Payment channel is InstaPay — merchants are free to receive through GCash or\n * Maya, both of which settle over InstaPay. Scan & Pay supports the QR Ph\n * standard only (wallet-proprietary GCash-only / Maya-only QRs are ignored),\n * mirroring how QRIS is handled for Indonesia, so PAY stays enabled.\n */\nexport const PHP_COUNTRY_OPTION: CountryOption = {\n\tcountry: \"Philippines\",\n\tcurrency: CURRENCY.PHP,\n\tsymbolNative: \"₱\",\n\tlocale: \"en-PH\",\n\tpaymentMethod: \"INSTAPAY\",\n\tpaymentAddressName: \"PHONE_NUMBER\",\n\ttimezone: \"Asia/Manila\",\n\ttimezone_name: \"PST\",\n\tflag: \"🇵🇭\",\n\tflagUrl: \"https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/72x72/1f1f5-1f1ed.png\",\n\tphoneCode: \"+63\",\n\ttelegramSupportChannel: \"https://t.me/p2pdotmeph\",\n\ttwitterUsername: \"p2pdotmeph\",\n\tsmsCountryCodes: [\"PH\"],\n\tprecision: 2,\n\tisAlpha: true,\n\tdisabled: false,\n\tdisabledPaymentTypes: [],\n\tgetPayQrPayload: (paymentId) => {\n\t\tconst candidate = payQrCandidate(paymentId);\n\t\treturn isPhilippinePayQr(candidate) ? candidate : null;\n\t},\n};\n","import { CURRENCY } from \"../currency\";\nimport type { CountryOption, PaymentIdFieldConfig } from \"../types\";\nimport { EUR_PLACEHOLDER, EUR_VALIDATION_ERROR, validateRevolutId } from \"./eur\";\n\nexport const USD_PLACEHOLDER = EUR_PLACEHOLDER;\nexport const USD_VALIDATION_ERROR = EUR_VALIDATION_ERROR;\n\n/** Payment ID field configuration for USD (Revolut USD). */\nexport const USD_PAYMENT_FIELDS: PaymentIdFieldConfig[] = [\n\t{\n\t\tkey: \"revolut\",\n\t\tlabel: \"REVOLUT_ID\",\n\t\tplaceholder: USD_PLACEHOLDER,\n\t\tdisplayLabel: \"Revolut ID\",\n\t\tvalidate: validateRevolutId,\n\t\tvalidationErrorMessage: USD_VALIDATION_ERROR,\n\t},\n];\n\n/** Country option for Revolut USD. */\nexport const USD_COUNTRY_OPTION: CountryOption = {\n\tcountry: \"Revolut USD\",\n\tcurrency: CURRENCY.USD,\n\tsymbolNative: \"$\",\n\tlocale: \"en-US\",\n\tpaymentMethod: \"REVOLUT\",\n\tpaymentAddressName: \"REVOLUT_ID\",\n\ttimezone: \"America/New_York\",\n\ttimezone_name: \"EST\",\n\tflag: \"\",\n\tflagUrl: \"https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/72x72/1f310.png\",\n\tphoneCode: \"+1\",\n\ttelegramSupportChannel: \"https://t.me/P2Pdotme\",\n\ttwitterUsername: \"P2Pdotme\",\n\tsmsCountryCodes: [\"US\"],\n\tprecision: 2,\n\tisAlpha: true,\n\tdisabled: true,\n\tdisabledPaymentTypes: [\"PAY\"],\n};\n","import { CURRENCY } from \"../currency\";\nimport { isVenezuelanPayQr, payQrCandidate, validateVenezuelanQr } from \"../qr-validator\";\nimport { type CountryOption, PACKED_PAYMENT_ID_SEP, type PaymentIdFieldConfig } from \"../types\";\n\nexport { validateVenezuelanQr };\n\nexport const VEN_PLACEHOLDER = \"04121234567\";\nexport const VEN_PLACEHOLDER_RIF = \"V12345678\";\nexport const VEN_PLACEHOLDER_BANK = \"Banesco\";\n\nexport const VEN_VALIDATION_ERROR = \"Please enter a valid phone number (e.g., 04121234567)\";\nexport const VEN_VALIDATION_ERROR_RIF =\n\t\"Please enter a valid Cédula/RIF (e.g., V12345678, P12345678)\";\nexport const VEN_VALIDATION_ERROR_BANK = \"Please enter a bank name\";\n\n/** Allowed Venezuelan document prefixes for Pago Móvil (SENIAT / banking). */\nexport const VEN_RIF_PREFIXES = [\"V\", \"E\", \"J\", \"G\", \"R\", \"P\"] as const;\n\n/**\n * Validates Venezuelan phone number for Pago Movil.\n * Format: 04XX-XXXXXXX (11 digits starting with 04).\n */\nexport function validateVenezuelanPhoneNumber(phoneNumber: string): boolean {\n\tif (!phoneNumber || phoneNumber.trim().length === 0) return false;\n\n\tconst cleaned = phoneNumber.trim().replace(/\\D/g, \"\");\n\n\tif (/^04\\d{9}$/.test(cleaned)) return true;\n\tif (/^4\\d{9}$/.test(cleaned)) return true;\n\n\treturn false;\n}\n\n/**\n * Validates Venezuelan Cédula/RIF for Pago Móvil.\n * Format: prefix (V|E|J|G|R|P) followed by digits.\n * Includes natural persons (V), foreigners (E), companies (J), government (G),\n * residual (R), and passport-linked accounts (P).\n */\nexport function validateVenezuelanRif(rif: string): boolean {\n\tif (!rif || rif.trim().length === 0) return false;\n\tconst trimmed = rif.trim().toUpperCase();\n\treturn /^[VEJGRP]\\d+$/.test(trimmed);\n}\n\nfunction isValidVenezuelanCompound(value: string): boolean {\n\tconst parts = value.split(\"|\");\n\tif (parts.length !== 3) return false;\n\treturn (\n\t\tvalidateVenezuelanPhoneNumber(parts[0]) &&\n\t\tvalidateVenezuelanRif(parts[1]) &&\n\t\tparts[2].trim().length > 0\n\t);\n}\n\nexport type VenezuelanPaymentIdParts = {\n\tqr: string | null;\n\tcompound: string | null;\n};\n\n/**\n * Splits a stored VEN payment ID into its QR payload and/or typed fallback.\n * Formats: S7B blob, `phone|rif|bank`, or `blob||phone|rif|bank`.\n */\nexport function parseVenezuelanPaymentId(\n\tvalue: string | null | undefined,\n): VenezuelanPaymentIdParts {\n\tif (!value || typeof value !== \"string\") return { qr: null, compound: null };\n\tconst trimmed = value.trim();\n\tconst sep = trimmed.indexOf(PACKED_PAYMENT_ID_SEP);\n\tif (sep >= 0) {\n\t\tconst left = trimmed.slice(0, sep);\n\t\tconst right = trimmed.slice(sep + PACKED_PAYMENT_ID_SEP.length);\n\t\treturn {\n\t\t\tqr: validateVenezuelanQr(left) ? left : null,\n\t\t\tcompound: isValidVenezuelanCompound(right) ? right : null,\n\t\t};\n\t}\n\tif (validateVenezuelanQr(trimmed)) return { qr: trimmed, compound: null };\n\tif (isValidVenezuelanCompound(trimmed)) return { qr: null, compound: trimmed };\n\treturn { qr: null, compound: null };\n}\n\nexport function serializeVenezuelanPaymentId(\n\tqr: string | null | undefined,\n\tcompound: string | null | undefined,\n): string {\n\tconst q = qr?.trim() && validateVenezuelanQr(qr.trim()) ? qr.trim() : \"\";\n\tconst c = compound?.trim() || \"\";\n\tif (q && c) return `${q}${PACKED_PAYMENT_ID_SEP}${c}`;\n\treturn q || c;\n}\n\n/**\n * Accepts a Suiche 7B QR payload, the typed `phone|rif|bank` fallback,\n * or both packed as `qr||phone|rif|bank`. A non-empty packed rest must be a\n * valid compound — QR does not mask an incomplete trio.\n */\nexport function validateVenezuelanPaymentId(value: string): boolean {\n\tif (!value || typeof value !== \"string\") return false;\n\tconst trimmed = value.trim();\n\tconst sep = trimmed.indexOf(PACKED_PAYMENT_ID_SEP);\n\tif (sep >= 0) {\n\t\tconst left = trimmed.slice(0, sep);\n\t\tconst right = trimmed.slice(sep + PACKED_PAYMENT_ID_SEP.length);\n\t\tconst qrOk = validateVenezuelanQr(left);\n\t\tif (right.trim()) return qrOk && isValidVenezuelanCompound(right);\n\t\treturn qrOk;\n\t}\n\tconst { qr, compound } = parseVenezuelanPaymentId(trimmed);\n\treturn qr !== null || compound !== null;\n}\n\n/** Payment ID field configuration for VEN (Venezuela, Pago Móvil). */\nexport const VEN_PAYMENT_FIELDS: PaymentIdFieldConfig[] = [\n\t{\n\t\tkey: \"phone\",\n\t\tlabel: \"PHONE_NUMBER\",\n\t\tplaceholder: VEN_PLACEHOLDER,\n\t\tdisplayLabel: \"Phone\",\n\t\tvalidate: validateVenezuelanPhoneNumber,\n\t\tvalidationErrorMessage: VEN_VALIDATION_ERROR,\n\t},\n\t{\n\t\tkey: \"rif\",\n\t\tlabel: \"RIF_LABEL\",\n\t\tplaceholder: VEN_PLACEHOLDER_RIF,\n\t\tdisplayLabel: \"Cédula/RIF\",\n\t\tvalidate: validateVenezuelanRif,\n\t\tvalidationErrorMessage: VEN_VALIDATION_ERROR_RIF,\n\t},\n\t{\n\t\tkey: \"bank\",\n\t\tlabel: \"BANK_LABEL\",\n\t\tplaceholder: VEN_PLACEHOLDER_BANK,\n\t\tdisplayLabel: \"Banco\",\n\t\tvalidate: (v: string) => v.trim().length > 0,\n\t\tvalidationErrorMessage: VEN_VALIDATION_ERROR_BANK,\n\t},\n];\n\n/** Country option for Venezuela (VEN). */\nexport const VEN_COUNTRY_OPTION: CountryOption = {\n\tcountry: \"Venezuela\",\n\tcurrency: CURRENCY.VEN,\n\tinternationalFormat: \"VES\",\n\tsymbolNative: \"Bs\",\n\tlocale: \"es-VE\",\n\tpaymentMethod: \"PAGO_MOVIL\",\n\tpaymentAddressName: \"PAGO_MOVIL_DETAILS\",\n\ttimezone: \"America/Caracas\",\n\ttimezone_name: \"VET\",\n\tflag: \"🇻🇪\",\n\tflagUrl: \"https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/72x72/1f1fb-1f1ea.png\",\n\tphoneCode: \"+58\",\n\ttelegramSupportChannel: \"https://t.me/p2pmevenezuela\",\n\ttwitterUsername: \"p2pmevenezuela\",\n\tsmsCountryCodes: [\"VE\"],\n\tprecision: 2,\n\tisAlpha: false,\n\tdisabled: false,\n\tdisabledPaymentTypes: [],\n\tuploadPaymentQR: true,\n\tvalidateQr: validateVenezuelanQr,\n\tgetPayQrPayload: (paymentId) => {\n\t\tconst candidate = payQrCandidate(paymentId);\n\t\treturn isVenezuelanPayQr(candidate) ? candidate : null;\n\t},\n};\n","import {\n\tARS_COUNTRY_OPTION,\n\tBOB_COUNTRY_OPTION,\n\tBRL_COUNTRY_OPTION,\n\tCOP_COUNTRY_OPTION,\n\tCUP_COUNTRY_OPTION,\n\tECU_COUNTRY_OPTION,\n\tEUR_COUNTRY_OPTION,\n\tIDR_COUNTRY_OPTION,\n\tINR_COUNTRY_OPTION,\n\tMEX_COUNTRY_OPTION,\n\tNGN_COUNTRY_OPTION,\n\tPEN_COUNTRY_OPTION,\n\tPHP_COUNTRY_OPTION,\n\tUSD_COUNTRY_OPTION,\n\tVEN_COUNTRY_OPTION,\n} from \"./currencies\";\nimport type { CurrencyCode } from \"./currency\";\nimport { PAYMENT_ID_FIELDS } from \"./payment-fields\";\nimport type { CountryOption } from \"./types\";\n\n/** All supported countries with their currency metadata, payment methods, and display config. */\nexport const COUNTRY_OPTIONS: readonly CountryOption[] = [\n\tINR_COUNTRY_OPTION,\n\tIDR_COUNTRY_OPTION,\n\tBRL_COUNTRY_OPTION,\n\tARS_COUNTRY_OPTION,\n\tMEX_COUNTRY_OPTION,\n\tVEN_COUNTRY_OPTION,\n\tBOB_COUNTRY_OPTION,\n\tNGN_COUNTRY_OPTION,\n\tCOP_COUNTRY_OPTION,\n\tCUP_COUNTRY_OPTION,\n\tECU_COUNTRY_OPTION,\n\tPEN_COUNTRY_OPTION,\n\tPHP_COUNTRY_OPTION,\n\tEUR_COUNTRY_OPTION,\n\tUSD_COUNTRY_OPTION,\n];\n\nexport function getCountryOption(\n\tcurrency: CurrencyCode | null | undefined,\n): CountryOption | undefined {\n\tif (!currency) return undefined;\n\treturn COUNTRY_OPTIONS.find((c) => c.currency === currency);\n}\n\n/**\n * Whether the merchant/seller provides payment details by uploading a QR image.\n * Distinct from PAY (`disabledPaymentTypes`), where the buyer scans a QR.\n */\nexport function uploadsPaymentQR(currency: CurrencyCode | null | undefined): boolean {\n\treturn getCountryOption(currency)?.uploadPaymentQR === true;\n}\n\n/**\n * Whether a stored payment ID may include a QR payload (`qr||fields` or\n * standalone QR). Derived from `validateQr` — no extra flag.\n */\nexport function usesPackedPaymentId(currency: CurrencyCode | null | undefined): boolean {\n\treturn getCountryOption(currency)?.validateQr != null;\n}\n\n/**\n * Apps mount the catalog form (PackedPaymentInput): QR upload and typed\n * fields may both show — they are not exclusive.\n */\nexport function usesCatalogPaymentForm(currency: CurrencyCode | null | undefined): boolean {\n\tif (!currency) return false;\n\treturn uploadsPaymentQR(currency) || (PAYMENT_ID_FIELDS[currency]?.length ?? 0) > 1;\n}\n\n/**\n * i18n key for a warning shown before the payer sends fiat, or `null` when the\n * currency has none. Apps translate with `t(key)` — do not branch on currency.\n */\nexport function getTransferWarning(currency: CurrencyCode | null | undefined): string | null {\n\treturn getCountryOption(currency)?.transferWarning ?? null;\n}\n","import { err, ok, type Result } from \"neverthrow\";\nimport { COUNTRY_OPTIONS } from \"../country\";\nimport type { CurrencyCode } from \"../types\";\nimport { QRParserError, type QRParserErrorCode } from \"./errors\";\n\n/** Currencies that support QR parsing — derived from countries where PAY is not disabled. */\nexport const SUPPORTED_QR_CURRENCIES: readonly CurrencyCode[] = COUNTRY_OPTIONS.filter(\n\t(c) => !c.disabledPaymentTypes.includes(\"PAY\"),\n).map((c) => c.currency);\n\nexport type SupportedCurrency = (typeof SUPPORTED_QR_CURRENCIES)[number];\n\n/** Internal — options forwarded to per-currency parsers (today, only PIX uses them). */\nexport interface ParseQRConfig {\n\tproxyUrl?: string;\n\torderId?: string;\n}\n\n/** Single-object params for `parseQR`. */\nexport interface ParseQRParams {\n\treadonly qrData: string;\n\treadonly currency: SupportedCurrency;\n\t/** Exchange rate: 1 USDC = `sellPrice` fiat. */\n\treadonly sellPrice: number;\n\t/** Required for dynamic PIX (BRL) QRs to bypass CORS on the bank endpoint. */\n\treadonly proxyUrl?: string;\n\t/** Forwarded to `proxyUrl` for tracing / correlation. */\n\treadonly orderId?: string;\n}\n\nexport interface ParsedQR {\n\tpaymentAddress: string;\n\tamount?: {\n\t\tusdc: number;\n\t\tfiat: number;\n\t};\n}\n\nexport type ParseResult = Result<ParsedQR, QRParserError>;\n\nexport function success(data: ParsedQR): ParseResult {\n\treturn ok(data);\n}\n\nexport function failure(\n\tcode: QRParserErrorCode,\n\tmessage: string,\n\tcontext?: Record<string, unknown>,\n): ParseResult {\n\treturn err(new QRParserError(message, { code, context }));\n}\n","/**\n * Calculate CRC-16-CCITT-FALSE checksum.\n * Polynomial 0x1021, initial value 0xFFFF.\n * Used by EMVCo-compliant QR codes (PIX, MercadoPago).\n */\nexport function calculateCRC16(data: string): string {\n\tconst payload = `${data}6304`;\n\tconst polynomial = 0x1021;\n\tlet result = 0xffff;\n\n\tconst encoder = new TextEncoder();\n\tconst bytes = encoder.encode(payload);\n\n\tfor (let offset = 0; offset < bytes.length; offset++) {\n\t\tresult ^= bytes[offset] << 8;\n\t\tfor (let bitwise = 0; bitwise < 8; bitwise++) {\n\t\t\tresult <<= 1;\n\t\t\tif (result & 0x10000) {\n\t\t\t\tresult ^= polynomial;\n\t\t\t}\n\t\t\tresult &= 0xffff;\n\t\t}\n\t}\n\n\treturn result.toString(16).toUpperCase().padStart(4, \"0\");\n}\n\n/**\n * Verify CRC-16 checksum of an EMVCo QR string.\n * Expects the string to end with \"6304\" + 4 hex CRC digits.\n */\nexport function verifyCRC16(qrData: string): { valid: boolean; error?: string } {\n\tif (!qrData || qrData.length < 8) {\n\t\treturn { valid: false, error: \"QR data too short for CRC verification\" };\n\t}\n\n\t// The CRC tag is always the final data object: \"63\" (tag) + \"04\" (length) +\n\t// 4 hex CRC digits. It must sit at a fixed position (length - 8). Locating it\n\t// positionally — rather than with lastIndexOf(\"6304\") — avoids a false match\n\t// when the CRC value itself is \"6304\" (payload ends \"...63046304\").\n\tconst crcTagIndex = qrData.length - 8;\n\tif (qrData.substring(crcTagIndex, crcTagIndex + 4) !== \"6304\") {\n\t\treturn { valid: false, error: \"Missing or misplaced CRC tag (6304)\" };\n\t}\n\n\tconst providedCrc = qrData.substring(crcTagIndex + 4, crcTagIndex + 8);\n\tif (!/^[0-9A-Fa-f]{4}$/.test(providedCrc)) {\n\t\treturn { valid: false, error: \"Invalid CRC hex format\" };\n\t}\n\n\tconst dataBeforeCrc = qrData.substring(0, crcTagIndex);\n\tconst calculatedCrc = calculateCRC16(dataBeforeCrc);\n\n\tif (calculatedCrc !== providedCrc.toUpperCase()) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terror: `CRC mismatch: expected ${calculatedCrc}, got ${providedCrc.toUpperCase()}`,\n\t\t};\n\t}\n\n\treturn { valid: true };\n}\n","/**\n * Parse a TLV (Tag-Length-Value) encoded string.\n * Tags are 2 digits, lengths are 2 digits (EMVCo standard).\n * Returns all parsed tag-value pairs. Stops gracefully on truncated data.\n */\nexport function parseTLV(data: string): { tag: string; value: string }[] {\n\tconst entries: { tag: string; value: string }[] = [];\n\tlet pos = 0;\n\n\twhile (pos + 4 <= data.length) {\n\t\tconst tag = data.substring(pos, pos + 2);\n\t\tconst lengthStr = data.substring(pos + 2, pos + 4);\n\n\t\tif (!/^[0-9]{2}$/.test(tag) || !/^[0-9]{2}$/.test(lengthStr)) {\n\t\t\tbreak;\n\t\t}\n\n\t\tconst length = parseInt(lengthStr, 10);\n\t\tif (pos + 4 + length > data.length) {\n\t\t\tbreak;\n\t\t}\n\n\t\tconst value = data.substring(pos + 4, pos + 4 + length);\n\t\tentries.push({ tag, value });\n\t\tpos += 4 + length;\n\t}\n\n\treturn entries;\n}\n\n/**\n * Extract specific tags from a TLV string.\n * Returns a record mapping tag IDs to their values.\n * Only includes tags present in the `tags` array.\n */\nexport function extractTags(data: string, tags: string[]): Record<string, string> {\n\tconst result: Record<string, string> = {};\n\tconst tagSet = new Set(tags);\n\n\tfor (const entry of parseTLV(data)) {\n\t\tif (tagSet.has(entry.tag)) {\n\t\t\tresult[entry.tag] = entry.value;\n\t\t}\n\t}\n\n\treturn result;\n}\n","import type { ParseResult } from \"../types\";\nimport { failure, success } from \"../types\";\nimport { verifyCRC16 } from \"../utils/crc16\";\nimport { extractTags } from \"../utils/tlv\";\n\nexport function parseMercadoPago(qrData: string, _sellPrice: number): ParseResult {\n\tif (!qrData || typeof qrData !== \"string\" || qrData.trim().length === 0) {\n\t\treturn failure(\"INVALID_QR\", \"QR data is empty or invalid\");\n\t}\n\n\tconst trimmed = qrData.trim();\n\n\tconst isARS = trimmed.includes(\"5303032\");\n\tconst isAR = trimmed.includes(\"5802AR\");\n\tif (!isARS && !isAR) {\n\t\treturn failure(\"INVALID_QR\", \"Not an ARS/Argentina QR code\");\n\t}\n\n\tconst crc = verifyCRC16(trimmed);\n\tif (!crc.valid) {\n\t\treturn failure(\"INVALID_QR\", \"Invalid QR checksum\");\n\t}\n\n\tconst tags = extractTags(trimmed, [\"59\"]);\n\tconst merchantName = tags[\"59\"] || \"Unknown\";\n\n\treturn success({ paymentAddress: merchantName });\n}\n","/** Plain decimal, EMVCo-style: digits with an optional single fractional part. */\nconst DECIMAL_AMOUNT = /^\\d+(\\.\\d+)?$/;\n\n/**\n * Parse a fiat amount string and convert to usdc using sellPrice.\n * Returns null unless the whole string is a finite, positive decimal amount and\n * sellPrice is a finite positive number. Rejects trailing garbage (\"12abc\"),\n * exponent/Infinity/NaN forms that parseFloat would otherwise accept, and a\n * zero/negative sellPrice that would produce an Infinite or negative usdc value.\n */\nexport function parseAmount(\n\tamountStr: string,\n\tsellPrice: number,\n): { usdc: number; fiat: number } | null {\n\tif (!amountStr) return null;\n\tconst trimmed = amountStr.trim();\n\tif (!DECIMAL_AMOUNT.test(trimmed)) return null;\n\n\tconst fiat = Number(trimmed);\n\tif (!Number.isFinite(fiat) || fiat <= 0) return null;\n\tif (!Number.isFinite(sellPrice) || sellPrice <= 0) return null;\n\n\treturn { usdc: fiat / sellPrice, fiat };\n}\n","import type { ParsedQR, ParseResult } from \"../types\";\nimport { failure, success } from \"../types\";\nimport { parseAmount } from \"../utils/amount\";\nimport { extractTags } from \"../utils/tlv\";\n\nconst BOB_TAGS = { AMOUNT: \"54\", CURRENCY: \"53\", COUNTRY: \"58\" } as const;\n\n/**\n * Bolivia QR Simple encrypted envelope: `<base64 ciphertext>|<hex checksum>`\n * (Yape Bs, BancoSol, Banco Fie dynamic QR). The payload is bank-encrypted, so\n * amount/account cannot be read — the buyer re-renders the exact blob for their\n * bank app to scan. The checksum is a hex digest whose length varies by bank\n * (24 hex for Banco Fie, 32 hex for Yape/BancoSol).\n */\nfunction isBolivianEncryptedQr(payload: string): boolean {\n\tif (payload.includes(\"||\")) return false;\n\tconst sep = payload.lastIndexOf(\"|\");\n\tif (sep < 40) return false;\n\tconst blob = payload.slice(0, sep);\n\tconst tag = payload.slice(sep + 1);\n\tif (blob.length % 4 !== 0) return false;\n\tif (!/^[A-Za-z0-9+/]+={0,2}$/.test(blob)) return false;\n\treturn /^(?:[0-9A-Fa-f]{24}|[0-9A-Fa-f]{32})$/.test(tag);\n}\n\n/**\n * Parses a Bolivian QR Simple QR. Accepts either the encrypted envelope\n * (`<base64>|<hex>`) or an EMVCo static QR (country tag 58 `BO`, currency tag\n * 53 `068`). Returns the raw payload verbatim as `paymentAddress` so the buyer app\n * can re-render the exact QR. Static EMVCo QRs carry no amount unless tag 54 is\n * present, which is converted to usdc via `sellPrice`; encrypted QRs carry none.\n */\nexport function parseBolivia(qrData: string, sellPrice: number): ParseResult {\n\tif (!qrData || typeof qrData !== \"string\" || qrData.trim().length === 0) {\n\t\treturn failure(\"INVALID_QR\", \"QR data is empty or invalid\");\n\t}\n\n\tconst trimmed = qrData.trim();\n\n\tif (isBolivianEncryptedQr(trimmed)) {\n\t\treturn success({ paymentAddress: trimmed });\n\t}\n\n\tconst tags = extractTags(trimmed, [BOB_TAGS.AMOUNT, BOB_TAGS.CURRENCY, BOB_TAGS.COUNTRY]);\n\n\tif (tags[BOB_TAGS.COUNTRY] !== \"BO\" || tags[BOB_TAGS.CURRENCY] !== \"068\") {\n\t\treturn failure(\"INVALID_QR\", \"Not a valid Bolivia QR Simple QR\");\n\t}\n\n\tconst result: ParsedQR = { paymentAddress: trimmed };\n\n\tconst amountStr = tags[BOB_TAGS.AMOUNT];\n\tif (amountStr) {\n\t\tconst amount = parseAmount(amountStr, sellPrice);\n\t\tif (!amount) {\n\t\t\treturn failure(\"INVALID_AMOUNT\", \"Invalid amount in QR\");\n\t\t}\n\t\tresult.amount = amount;\n\t}\n\n\treturn success(result);\n}\n","import { err, ok, type Result } from \"neverthrow\";\nimport { QRParserError, type QRParserErrorCode } from \"../errors\";\nimport type { ParsedQR, ParseQRConfig, ParseResult } from \"../types\";\nimport { failure, success } from \"../types\";\nimport { parseAmount } from \"../utils/amount\";\nimport { verifyCRC16 } from \"../utils/crc16\";\nimport { parseTLV } from \"../utils/tlv\";\n\nconst PIX_TAGS = {\n\tPAYLOAD_FORMAT: \"00\",\n\tPIX_KEY_INFO: \"26\",\n\tAMOUNT: \"54\",\n\tMERCHANT_NAME: \"59\",\n\tCRC: \"63\",\n} as const;\n\nfunction parsePIXKeyInfo(data: string): { pixKey: string | null; location: string | null } {\n\tconst result = { pixKey: null as string | null, location: null as string | null };\n\n\tfor (const entry of parseTLV(data)) {\n\t\tif (entry.tag === \"01\") {\n\t\t\tif (entry.value.includes(\"http\") || entry.value.includes(\"://\")) {\n\t\t\t\tresult.location = entry.value.startsWith(\"http\") ? entry.value : `https://${entry.value}`;\n\t\t\t} else {\n\t\t\t\tresult.pixKey = entry.value;\n\t\t\t}\n\t\t} else if (entry.tag === \"25\") {\n\t\t\tresult.location = entry.value.startsWith(\"http\") ? entry.value : `https://${entry.value}`;\n\t\t}\n\t}\n\n\treturn result;\n}\n\nfunction safeBase64Decode(base64String: string): string {\n\tif (typeof globalThis.atob === \"function\") {\n\t\treturn globalThis.atob(base64String);\n\t}\n\tthrow new Error(\"No base64 decoder available\");\n}\n\ninterface PIXJWTPayload {\n\tstatus?: string;\n\ttxid?: string;\n\tvalor?: { original?: string };\n\tcalendario?: { expiracao?: number };\n}\n\nfunction parseJWT(token: string): PIXJWTPayload | null {\n\ttry {\n\t\tconst parts = token.trim().split(\".\");\n\t\tif (parts.length !== 3 || !parts[0] || !parts[1] || !parts[2]) return null;\n\t\tconst json = safeBase64Decode(parts[1]);\n\t\treturn JSON.parse(json) as PIXJWTPayload;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction dynamicErr(\n\tcode: QRParserErrorCode,\n\tmessage: string,\n): Result<{ dynamicAmount?: string }, QRParserError> {\n\treturn err(new QRParserError(message, { code }));\n}\n\nasync function fetchDynamicData(\n\tlocation: string,\n\tproxyUrl: string,\n\torderId?: string,\n): Promise<Result<{ dynamicAmount?: string }, QRParserError>> {\n\ttry {\n\t\tconst url = new URL(`${proxyUrl}/pix`);\n\t\turl.searchParams.set(\"locationUrl\", location);\n\t\tif (orderId) {\n\t\t\turl.searchParams.set(\"orderId\", orderId);\n\t\t}\n\n\t\tconst response = await fetch(url, {\n\t\t\tmethod: \"GET\",\n\t\t\theaders: { Accept: \"*/*\" },\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\treturn dynamicErr(\"FETCH_FAILED\", `Proxy error: ${response.status} ${response.statusText}`);\n\t\t}\n\n\t\tconst jwtToken = await response.text();\n\t\tconst payload = parseJWT(jwtToken);\n\n\t\tif (!payload) {\n\t\t\treturn dynamicErr(\"FETCH_FAILED\", \"Failed to parse dynamic PIX response\");\n\t\t}\n\n\t\treturn ok({ dynamicAmount: payload.valor?.original });\n\t} catch (error) {\n\t\tconst msg = error instanceof Error ? error.message : \"Unknown error\";\n\t\treturn dynamicErr(\"FETCH_FAILED\", `Failed to fetch dynamic PIX data: ${msg}`);\n\t}\n}\n\nexport async function parsePIX(\n\tqrData: string,\n\tsellPrice: number,\n\tconfig: ParseQRConfig,\n): Promise<ParseResult> {\n\tif (!qrData || typeof qrData !== \"string\" || qrData.trim().length === 0) {\n\t\treturn failure(\"INVALID_QR\", \"QR data is empty or invalid\");\n\t}\n\n\tconst trimmed = qrData.trim();\n\n\tconst crc = verifyCRC16(trimmed);\n\tif (!crc.valid) {\n\t\treturn failure(\"INVALID_QR\", \"Invalid QR checksum\");\n\t}\n\n\tconst allTags: Record<string, string> = {};\n\tfor (const entry of parseTLV(trimmed)) {\n\t\tallTags[entry.tag] = entry.value;\n\t}\n\n\tif (!allTags[PIX_TAGS.PAYLOAD_FORMAT]) {\n\t\treturn failure(\"INVALID_QR\", \"Invalid PIX QR format\");\n\t}\n\n\tconst merchantName = allTags[PIX_TAGS.MERCHANT_NAME] || \"MERCHANT_NOT_FOUND\";\n\n\tlet dynamicAmount: string | undefined;\n\tconst pixKeyData = allTags[PIX_TAGS.PIX_KEY_INFO];\n\tif (pixKeyData) {\n\t\tconst { location } = parsePIXKeyInfo(pixKeyData);\n\t\tif (location) {\n\t\t\tif (!config.proxyUrl) {\n\t\t\t\treturn failure(\"FETCH_FAILED\", \"proxyUrl is required for dynamic PIX QR codes\");\n\t\t\t}\n\t\t\tconst dynamicResult = await fetchDynamicData(location, config.proxyUrl, config.orderId);\n\t\t\tif (dynamicResult.isErr()) {\n\t\t\t\treturn err(dynamicResult.error);\n\t\t\t}\n\t\t\tdynamicAmount = dynamicResult.value.dynamicAmount;\n\t\t}\n\t}\n\n\tconst fiatAmountStr = dynamicAmount || allTags[PIX_TAGS.AMOUNT];\n\tconst result: ParsedQR = { paymentAddress: merchantName };\n\n\tif (fiatAmountStr) {\n\t\tconst amount = parseAmount(fiatAmountStr, sellPrice);\n\t\tif (amount) {\n\t\t\tresult.amount = amount;\n\t\t}\n\t}\n\n\treturn success(result);\n}\n","import type { ParsedQR, ParseResult } from \"../types\";\nimport { failure, success } from \"../types\";\nimport { parseAmount } from \"../utils/amount\";\nimport { extractTags } from \"../utils/tlv\";\n\nconst COP_CURRENCY_CODE = \"5303170\";\nconst CO_COUNTRY_CODE = \"5802CO\";\n\nconst DIAN_KEYS = [\"NumFac\", \"CUFE\", \"Cufe\", \"NitFac\", \"ValFac\", \"ValTolFac\"] as const;\n\nfunction parseDianInvoice(qrData: string): ParseResult | null {\n\tconst hasDianMarker = DIAN_KEYS.some(\n\t\t(k) => qrData.includes(`${k}:`) || qrData.includes(`${k} :`),\n\t);\n\tif (!hasDianMarker) return null;\n\n\tconst fields: Record<string, string> = {};\n\tconst segments = qrData.split(/[\\n,;]+/);\n\tfor (const segment of segments) {\n\t\tconst idx = segment.indexOf(\":\");\n\t\tif (idx === -1) continue;\n\t\tconst key = segment.substring(0, idx).trim();\n\t\tconst value = segment.substring(idx + 1).trim();\n\t\tif (key && value && !fields[key]) fields[key] = value;\n\t}\n\n\tconst cufe = fields.CUFE || fields.Cufe || fields.cufe;\n\tconst numFac = fields.NumFac;\n\tconst paymentAddress = cufe || numFac;\n\n\tif (!paymentAddress) {\n\t\treturn failure(\"INVALID_QR\", \"Missing CUFE / NumFac in DIAN invoice QR\");\n\t}\n\n\treturn success({ paymentAddress });\n}\n\nfunction parseColombianEMV(qrData: string, sellPrice: number): ParseResult | null {\n\tconst isCO = qrData.includes(CO_COUNTRY_CODE);\n\tconst isCOP = qrData.includes(COP_CURRENCY_CODE);\n\tif (!isCO || !isCOP) return null;\n\n\tconst tags = extractTags(qrData, [\"54\", \"59\"]);\n\tconst merchantName = tags[\"59\"] || \"MERCHANT_NOT_FOUND\";\n\n\tconst result: ParsedQR = { paymentAddress: merchantName };\n\n\tconst amountStr = tags[\"54\"];\n\tif (amountStr) {\n\t\tconst amount = parseAmount(amountStr, sellPrice);\n\t\tif (amount) result.amount = amount;\n\t}\n\n\treturn success(result);\n}\n\n/**\n * Parses a Colombian QR. Supports DIAN electronic invoice QRs\n * (key:value text with `CUFE`/`NumFac`) and EMVCo-encoded QRs from\n * Colombian payment networks (Nequi, Bre-B/RBM) identified by country\n * `5802CO` and currency `5303170`.\n */\nexport function parseCOP(qrData: string, sellPrice: number): ParseResult {\n\tif (!qrData || typeof qrData !== \"string\" || qrData.trim().length === 0) {\n\t\treturn failure(\"INVALID_QR\", \"QR data is empty or invalid\");\n\t}\n\n\tconst trimmed = qrData.trim();\n\n\tconst dian = parseDianInvoice(trimmed);\n\tif (dian) return dian;\n\n\tconst emv = parseColombianEMV(trimmed, sellPrice);\n\tif (emv) return emv;\n\n\treturn failure(\"INVALID_QR\", \"Not a recognized Colombian QR code\");\n}\n","import type { ParsedQR, ParseResult } from \"../types\";\nimport { failure, success } from \"../types\";\nimport { parseAmount } from \"../utils/amount\";\n\nconst TRANSFERMOVIL_PREFIX = \"TRANSFERMOVIL_ETECSA\";\n\nconst CARD_INDEX = 2;\nconst PHONE_INDEX = 3;\nconst AMOUNT_INDEX = 4;\n\nfunction normalizePhone(phone: string): string | null {\n\tconst cleaned = phone.replace(/\\D/g, \"\");\n\tif (/^\\d{8}$/.test(cleaned)) return cleaned;\n\tif (/^53\\d{8}$/.test(cleaned)) return cleaned.slice(2);\n\treturn null;\n}\n\nfunction normalizeCard(card: string): string | null {\n\tconst cleaned = card.replace(/[\\s-]/g, \"\");\n\treturn /^\\d{16}$/.test(cleaned) ? cleaned : null;\n}\n\n/**\n * Parses a Cuban Transfermóvil QR code\n * (`TRANSFERMOVIL_ETECSA,<operation>,<card>,<phone>,<amount>`) and returns the\n * payment address as the compound `phone|card` pair used for CUP. The amount\n * field is optional — when present it is converted to usdc via `sellPrice`.\n */\nexport function parseTransfermovil(qrData: string, sellPrice: number): ParseResult {\n\tif (!qrData || typeof qrData !== \"string\" || qrData.trim().length === 0) {\n\t\treturn failure(\"INVALID_QR\", \"QR data is empty or invalid\");\n\t}\n\n\tconst trimmed = qrData.trim();\n\tconst parts = trimmed.split(\",\").map((p) => p.trim());\n\n\tif (parts[0]?.toUpperCase() !== TRANSFERMOVIL_PREFIX) {\n\t\treturn failure(\"INVALID_QR\", \"Not a valid Cuban (Transfermóvil) QR code\");\n\t}\n\n\tif (parts.length <= PHONE_INDEX) {\n\t\treturn failure(\"INVALID_QR\", \"Transfermóvil QR is missing card or phone fields\");\n\t}\n\n\tconst card = normalizeCard(parts[CARD_INDEX] ?? \"\");\n\tif (!card) {\n\t\treturn failure(\"INVALID_QR\", \"Transfermóvil QR has an invalid card number\");\n\t}\n\n\tconst phone = normalizePhone(parts[PHONE_INDEX] ?? \"\");\n\tif (!phone) {\n\t\treturn failure(\"INVALID_QR\", \"Transfermóvil QR has an invalid phone number\");\n\t}\n\n\tconst result: ParsedQR = { paymentAddress: `${phone}|${card}` };\n\n\tconst amountStr = parts[AMOUNT_INDEX];\n\tif (amountStr) {\n\t\tconst amount = parseAmount(amountStr, sellPrice);\n\t\tif (!amount) {\n\t\t\treturn failure(\"INVALID_AMOUNT\", \"Invalid amount in QR\");\n\t\t}\n\t\tresult.amount = amount;\n\t}\n\n\treturn success(result);\n}\n","import type { ParseResult } from \"../types\";\nimport { failure, success } from \"../types\";\n\nconst DEUNA_HOST = \"pagar.deuna.app\";\n\n/**\n * Parses a DeUna (Banco Pichincha, Ecuador) payment QR. DeUna QRs are plain URLs of\n * the form `https://pagar.deuna.app/<slug>/merchant?id=<hash>`; the `id` query param\n * is the merchant payment address. DeUna QRs carry no amount, so `_sellPrice` is unused.\n */\nexport function parseDeUna(qrData: string, _sellPrice: number): ParseResult {\n\tif (!qrData || typeof qrData !== \"string\" || qrData.trim().length === 0) {\n\t\treturn failure(\"INVALID_QR\", \"QR data is empty or invalid\");\n\t}\n\n\tlet url: URL;\n\ttry {\n\t\turl = new URL(qrData.trim());\n\t} catch {\n\t\treturn failure(\"INVALID_QR\", \"Not a valid DeUna URL\");\n\t}\n\n\tif (url.hostname !== DEUNA_HOST) {\n\t\treturn failure(\"INVALID_QR\", `Unexpected DeUna host: ${url.hostname}`);\n\t}\n\n\tconst id = url.searchParams.get(\"id\");\n\tif (!id) {\n\t\treturn failure(\"INVALID_QR\", \"Missing DeUna merchant id\");\n\t}\n\n\treturn success({ paymentAddress: id });\n}\n","import type { ParsedQR, ParseResult } from \"../types\";\nimport { failure, success } from \"../types\";\nimport { parseAmount } from \"../utils/amount\";\nimport { extractTags } from \"../utils/tlv\";\n\nconst QRIS_TAGS = { AMOUNT: \"54\", MERCHANT_NAME: \"59\" } as const;\n\nexport function parseQRIS(qrData: string, sellPrice: number): ParseResult {\n\tif (!qrData || typeof qrData !== \"string\" || qrData.trim().length === 0) {\n\t\treturn failure(\"INVALID_QR\", \"QR data is empty or invalid\");\n\t}\n\n\tconst trimmed = qrData.trim();\n\tconst tags = extractTags(trimmed, [QRIS_TAGS.AMOUNT, QRIS_TAGS.MERCHANT_NAME]);\n\n\tconst merchantName = tags[QRIS_TAGS.MERCHANT_NAME];\n\tif (!merchantName) {\n\t\treturn failure(\"INVALID_QR\", \"Missing merchant name\");\n\t}\n\n\tconst result: ParsedQR = { paymentAddress: merchantName };\n\n\tconst amountStr = tags[QRIS_TAGS.AMOUNT];\n\tif (amountStr) {\n\t\tconst amount = parseAmount(amountStr, sellPrice);\n\t\tif (!amount) {\n\t\t\treturn failure(\"INVALID_AMOUNT\", \"Invalid amount in QR\");\n\t\t}\n\t\tresult.amount = amount;\n\t}\n\n\treturn success(result);\n}\n","import type { ParsedQR, ParseResult } from \"../types\";\nimport { failure, success } from \"../types\";\nimport { parseAmount } from \"../utils/amount\";\n\nconst UPI_ID_REGEX = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+$/;\n\nexport function parseUPI(qrData: string, sellPrice: number): ParseResult {\n\tif (!qrData || typeof qrData !== \"string\" || qrData.trim().length === 0) {\n\t\treturn failure(\"INVALID_QR\", \"QR data is empty or invalid\");\n\t}\n\n\tconst trimmed = qrData.trim();\n\n\tlet paramString: string;\n\tif (trimmed.startsWith(\"upi://pay?\")) {\n\t\tparamString = trimmed.substring(10);\n\t} else if (trimmed.includes(\"?\")) {\n\t\tparamString = trimmed.split(\"?\")[1];\n\t} else {\n\t\tparamString = trimmed;\n\t}\n\n\tconst params = new URLSearchParams(paramString);\n\tconst pa = params.get(\"pa\");\n\n\tif (!pa) {\n\t\treturn failure(\"INVALID_QR\", \"Missing UPI payment address\");\n\t}\n\n\tif (!UPI_ID_REGEX.test(pa)) {\n\t\treturn failure(\"INVALID_QR\", \"Invalid UPI ID format\");\n\t}\n\n\tconst result: ParsedQR = { paymentAddress: pa };\n\n\tconst amountStr = params.get(\"am\");\n\tif (amountStr) {\n\t\tconst amount = parseAmount(amountStr, sellPrice);\n\t\tif (!amount) {\n\t\t\treturn failure(\"INVALID_AMOUNT\", \"Invalid amount in QR\");\n\t\t}\n\t\tresult.amount = amount;\n\t}\n\n\treturn success(result);\n}\n","import type { ParsedQR, ParseResult } from \"../types\";\nimport { failure, success } from \"../types\";\nimport { parseAmount } from \"../utils/amount\";\nimport { verifyCRC16 } from \"../utils/crc16\";\nimport { extractTags, parseTLV } from \"../utils/tlv\";\n\nconst NGN_TAGS = {\n\tAMOUNT: \"54\",\n\tCURRENCY: \"53\",\n\tCOUNTRY: \"58\",\n\tMERCHANT_NAME: \"59\",\n} as const;\n\nconst NGN_CURRENCY_CODE = \"566\";\nconst NIBSS_AID = \"NG.COM.NIBSSPLC.QR\";\n\nfunction isNQR(qrData: string): boolean {\n\tif (qrData.includes(NIBSS_AID)) return true;\n\tif (qrData.includes(`5303${NGN_CURRENCY_CODE}`)) return true;\n\tif (qrData.includes(\"5802NG\")) return true;\n\treturn false;\n}\n\nfunction parseEMVCoNQR(qrData: string, sellPrice: number): ParseResult {\n\tconst crc = verifyCRC16(qrData);\n\tif (!crc.valid) {\n\t\treturn failure(\"INVALID_QR\", \"Invalid QR checksum\");\n\t}\n\n\tif (!isNQR(qrData)) {\n\t\treturn failure(\"INVALID_QR\", \"Not a Nigerian (NQR) QR code\");\n\t}\n\n\tconst tags = extractTags(qrData, [NGN_TAGS.AMOUNT, NGN_TAGS.MERCHANT_NAME]);\n\n\tconst merchantName = tags[NGN_TAGS.MERCHANT_NAME];\n\tif (!merchantName) {\n\t\treturn failure(\"INVALID_QR\", \"Missing merchant name\");\n\t}\n\n\tconst result: ParsedQR = { paymentAddress: merchantName };\n\n\tconst amountStr = tags[NGN_TAGS.AMOUNT];\n\tif (amountStr) {\n\t\tconst amount = parseAmount(amountStr, sellPrice);\n\t\tif (!amount) {\n\t\t\treturn failure(\"INVALID_AMOUNT\", \"Invalid amount in QR\");\n\t\t}\n\t\tresult.amount = amount;\n\t}\n\n\treturn success(result);\n}\n\nfunction parseSPD(qrData: string, sellPrice: number): ParseResult {\n\t// Short Payment Descriptor (Czech spec). Seen in the wild for some\n\t// Nigerian account-based QRs: `SPD*1.0*ACC:<nuban>*AM:<amount>*MSG:<text>*`.\n\tconst parts = qrData.split(\"*\").filter((p) => p.length > 0);\n\tif (parts.length < 2 || parts[0] !== \"SPD\") {\n\t\treturn failure(\"INVALID_QR\", \"Not a valid SPD QR code\");\n\t}\n\n\tconst fields: Record<string, string> = {};\n\tfor (const part of parts.slice(2)) {\n\t\tconst colon = part.indexOf(\":\");\n\t\tif (colon === -1) continue;\n\t\tfields[part.substring(0, colon).toUpperCase()] = part.substring(colon + 1);\n\t}\n\n\tconst account = fields.ACC;\n\tif (!account) {\n\t\treturn failure(\"INVALID_QR\", \"Missing ACC field in SPD QR\");\n\t}\n\n\tconst result: ParsedQR = { paymentAddress: account };\n\n\tconst amountStr = fields.AM;\n\tif (amountStr) {\n\t\tconst amount = parseAmount(amountStr.replace(/,/g, \"\"), sellPrice);\n\t\tif (!amount) {\n\t\t\treturn failure(\"INVALID_AMOUNT\", \"Invalid amount in QR\");\n\t\t}\n\t\tresult.amount = amount;\n\t}\n\n\treturn success(result);\n}\n\n/**\n * Parses a Nigerian QR code. Supports NIBSS NQR (EMVCo MPM with AID\n * `NG.COM.NIBSSPLC.QR`) and the SPD `SPD*1.0*ACC:...*AM:...*` format.\n */\nexport function parseNGN(qrData: string, sellPrice: number): ParseResult {\n\tif (!qrData || typeof qrData !== \"string\" || qrData.trim().length === 0) {\n\t\treturn failure(\"INVALID_QR\", \"QR data is empty or invalid\");\n\t}\n\n\tconst trimmed = qrData.trim();\n\n\tif (trimmed.startsWith(\"SPD*\")) {\n\t\treturn parseSPD(trimmed, sellPrice);\n\t}\n\n\t// Sanity-check that this looks like EMVCo TLV before CRC-ing.\n\tif (parseTLV(trimmed).length === 0) {\n\t\treturn failure(\"INVALID_QR\", \"Not a valid Nigerian QR code\");\n\t}\n\n\treturn parseEMVCoNQR(trimmed, sellPrice);\n}\n","import { validatePeruvianQr } from \"../../country/qr-validator\";\nimport type { ParsedQR, ParseResult } from \"../types\";\nimport { failure, success } from \"../types\";\nimport { parseAmount } from \"../utils/amount\";\nimport { extractTags } from \"../utils/tlv\";\n\nconst PEN_TAGS = { AMOUNT: \"54\" } as const;\n\n/**\n * Parses a Peruvian Yape/Plin EMVCo QR. Uses the same structural + CRC check\n * as SELL upload (`validatePeruvianQr`: country PE, currency 604, CRC-16).\n * Returns the raw payload verbatim as `paymentAddress` so the merchant can\n * re-render the exact QR. Static QRs carry no amount; tag 54 converts via\n * `sellPrice`.\n */\nexport function parsePeru(qrData: string, sellPrice: number): ParseResult {\n\tif (!qrData || typeof qrData !== \"string\" || qrData.trim().length === 0) {\n\t\treturn failure(\"INVALID_QR\", \"QR data is empty or invalid\");\n\t}\n\n\tconst trimmed = qrData.trim();\n\tif (!validatePeruvianQr(trimmed)) {\n\t\treturn failure(\"INVALID_QR\", \"Not a valid Peru Yape/Plin QR\");\n\t}\n\n\tconst tags = extractTags(trimmed, [PEN_TAGS.AMOUNT]);\n\tconst result: ParsedQR = { paymentAddress: trimmed };\n\n\tconst amountStr = tags[PEN_TAGS.AMOUNT];\n\tif (amountStr) {\n\t\tconst amount = parseAmount(amountStr, sellPrice);\n\t\tif (!amount) {\n\t\t\treturn failure(\"INVALID_AMOUNT\", \"Invalid amount in QR\");\n\t\t}\n\t\tresult.amount = amount;\n\t}\n\n\treturn success(result);\n}\n","import type { ParsedQR, ParseResult } from \"../types\";\nimport { failure, success } from \"../types\";\nimport { parseAmount } from \"../utils/amount\";\nimport { verifyCRC16 } from \"../utils/crc16\";\nimport { extractTags } from \"../utils/tlv\";\n\nconst PHP_TAGS = { AMOUNT: \"54\", CURRENCY: \"53\", COUNTRY: \"58\" } as const;\n\n/**\n * Parses a Philippine QR Ph EMVCo QR. Validates it is a genuine QR Ph\n * (country tag 58 `PH`, currency tag 53 `608`, valid CRC) and returns the raw\n * payload verbatim as `paymentAddress` so the buyer app can re-render the exact\n * QR. Wallet-proprietary GCash-only / Maya-only QRs are not QR Ph and are\n * rejected by the country/currency check. Static QRs carry no amount; when tag\n * 54 is present it is converted to usdc via `sellPrice`.\n */\nexport function parseQRPh(qrData: string, sellPrice: number): ParseResult {\n\tif (!qrData || typeof qrData !== \"string\" || qrData.trim().length === 0) {\n\t\treturn failure(\"INVALID_QR\", \"QR data is empty or invalid\");\n\t}\n\n\tconst trimmed = qrData.trim();\n\tconst tags = extractTags(trimmed, [PHP_TAGS.AMOUNT, PHP_TAGS.CURRENCY, PHP_TAGS.COUNTRY]);\n\n\tif (tags[PHP_TAGS.COUNTRY] !== \"PH\" || tags[PHP_TAGS.CURRENCY] !== \"608\") {\n\t\treturn failure(\"INVALID_QR\", \"Not a valid QR Ph code\");\n\t}\n\n\tconst crc = verifyCRC16(trimmed);\n\tif (!crc.valid) {\n\t\treturn failure(\"INVALID_QR\", crc.error ?? \"Invalid QR Ph checksum\");\n\t}\n\n\tconst result: ParsedQR = { paymentAddress: trimmed };\n\n\tconst amountStr = tags[PHP_TAGS.AMOUNT];\n\tif (amountStr) {\n\t\tconst amount = parseAmount(amountStr, sellPrice);\n\t\tif (!amount) {\n\t\t\treturn failure(\"INVALID_AMOUNT\", \"Invalid amount in QR\");\n\t\t}\n\t\tresult.amount = amount;\n\t}\n\n\treturn success(result);\n}\n","import { validateVenezuelanQr } from \"../../country/qr-validator\";\nimport type { ParseResult } from \"../types\";\nimport { failure, success } from \"../types\";\n\n/**\n * Same envelope as SELL upload: opaque `base64?merchantId=NNNN` (blob ≥ 40).\n * Prefer `validateVenezuelanQr` from `@p2pdotme/sdk/country`; this alias stays\n * for `@p2pdotme/sdk/qr-parsers` callers.\n */\nexport function isPagoMovilQr(qrData: string): boolean {\n\treturn validateVenezuelanQr(qrData);\n}\n\n/**\n * Parses a Venezuelan Pago Móvil / Suiche 7B QR. Uses the same envelope as\n * SELL upload (`validateVenezuelanQr`). Returns the raw payload verbatim as\n * `paymentAddress` so the merchant can re-render the exact QR.\n */\nexport function parsePagoMovil(qrData: string, _sellPrice: number): ParseResult {\n\tif (!qrData || typeof qrData !== \"string\" || qrData.trim().length === 0) {\n\t\treturn failure(\"INVALID_QR\", \"QR data is empty or invalid\");\n\t}\n\n\tconst trimmed = qrData.trim();\n\tif (!validateVenezuelanQr(trimmed)) {\n\t\treturn failure(\"INVALID_QR\", \"Not a valid Venezuelan QR code\");\n\t}\n\n\treturn success({ paymentAddress: trimmed });\n}\n","import { CURRENCY, getCountryOption } from \"../country\";\nimport { parseMercadoPago } from \"./parsers/ars\";\nimport { parseBolivia } from \"./parsers/bob\";\nimport { parsePIX } from \"./parsers/brl\";\nimport { parseCOP } from \"./parsers/cop\";\nimport { parseTransfermovil } from \"./parsers/cup\";\nimport { parseDeUna } from \"./parsers/ecu\";\nimport { parseQRIS } from \"./parsers/idr\";\nimport { parseUPI } from \"./parsers/inr\";\nimport { parseNGN } from \"./parsers/ngn\";\nimport { parsePeru } from \"./parsers/pen\";\nimport { parseQRPh } from \"./parsers/php\";\nimport { parsePagoMovil } from \"./parsers/ven\";\nimport type { ParseQRParams, ParseResult } from \"./types\";\nimport { failure } from \"./types\";\n\n/**\n * Parses a QR string for the given currency and returns the extracted payment data.\n *\n * This dispatcher is `async` because dynamic PIX (BRL) QRs store the amount\n * behind a location URL pointing at the issuing bank's PIX endpoint. The SDK\n * resolves that URL via a CORS-bypassing proxy (see `proxyUrl`), which returns\n * a signed JWT whose `valor.original` field holds the amount. All other parsers\n * (UPI, QRIS, QR Ph, MercadoPago, PagoMovil, Transfermóvil) and static PIX are synchronous and\n * resolve immediately.\n *\n * When the country has `validateQr` (PEN, VEN, BOB), Scan & Pay must pass the\n * same check as SELL upload — not a looser envelope.\n */\nexport async function parseQR(params: ParseQRParams): Promise<ParseResult> {\n\tconst { qrData, currency, sellPrice, proxyUrl, orderId } = params;\n\n\tif (!qrData || typeof qrData !== \"string\" || qrData.trim().length === 0) {\n\t\treturn failure(\"INVALID_QR\", \"QR data is empty or invalid\");\n\t}\n\n\tlet result: ParseResult;\n\tswitch (currency) {\n\t\tcase CURRENCY.INR:\n\t\t\tresult = parseUPI(qrData, sellPrice);\n\t\t\tbreak;\n\t\tcase CURRENCY.IDR:\n\t\t\tresult = parseQRIS(qrData, sellPrice);\n\t\t\tbreak;\n\t\tcase CURRENCY.BRL:\n\t\t\tresult = await parsePIX(qrData, sellPrice, { proxyUrl, orderId });\n\t\t\tbreak;\n\t\tcase CURRENCY.ARS:\n\t\t\tresult = parseMercadoPago(qrData, sellPrice);\n\t\t\tbreak;\n\t\tcase CURRENCY.VEN:\n\t\t\tresult = parsePagoMovil(qrData, sellPrice);\n\t\t\tbreak;\n\t\tcase CURRENCY.BOB:\n\t\t\tresult = parseBolivia(qrData, sellPrice);\n\t\t\tbreak;\n\t\tcase CURRENCY.NGN:\n\t\t\tresult = parseNGN(qrData, sellPrice);\n\t\t\tbreak;\n\t\tcase CURRENCY.COP:\n\t\t\tresult = parseCOP(qrData, sellPrice);\n\t\t\tbreak;\n\t\tcase CURRENCY.CUP:\n\t\t\tresult = parseTransfermovil(qrData, sellPrice);\n\t\t\tbreak;\n\t\tcase CURRENCY.ECU:\n\t\t\tresult = parseDeUna(qrData, sellPrice);\n\t\t\tbreak;\n\t\tcase CURRENCY.PEN:\n\t\t\tresult = parsePeru(qrData, sellPrice);\n\t\t\tbreak;\n\t\tcase CURRENCY.PHP:\n\t\t\tresult = parseQRPh(qrData, sellPrice);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\treturn failure(\"INVALID_CURRENCY\", `Currency \"${currency}\" is not supported`);\n\t}\n\n\tconst validateQr = getCountryOption(currency)?.validateQr;\n\tif (result.isOk() && validateQr && !validateQr(qrData.trim())) {\n\t\treturn failure(\"INVALID_QR\", \"QR does not match catalog validateQr\");\n\t}\n\n\treturn result;\n}\n"],"mappings":"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","names":["isBolivianEncryptedQr","import_neverthrow"]}