fix: add retry to getPayment, normalize return, env validation, webhook/builder tests

This commit is contained in:
Kirill
2026-05-20 18:11:14 +05:00
parent a3556367c6
commit abadbbd4c4
2 changed files with 122 additions and 10 deletions
+17 -8
View File
@@ -3,6 +3,9 @@ const YOOKASSA_API_URL = 'https://api.yookassa.ru/v3'
function getAuthHeader() {
const shopId = process.env.YOOKASSA_SHOP_ID
const secretKey = process.env.YOOKASSA_SECRET_KEY
if (!shopId || !secretKey) {
throw new Error('YOOKASSA_SHOP_ID and YOOKASSA_SECRET_KEY are required')
}
const token = Buffer.from(`${shopId}:${secretKey}`).toString('base64')
return `Basic ${token}`
}
@@ -31,7 +34,7 @@ async function fetchWithRetry(url, opts, maxRetries = 3) {
)
} catch (err) {
if (err instanceof Error && err.message.startsWith('YooKassa API error')) throw err
lastError = err
lastError = new Error(`YooKassa API error: network failure — ${err instanceof Error ? err.message : String(err)}`)
if (attempt === maxRetries) throw lastError
}
}
@@ -86,14 +89,18 @@ export async function createPayment({
}
export async function getPayment(paymentId) {
const res = await fetch(`${YOOKASSA_API_URL}/payments/${paymentId}`, {
const res = await fetchWithRetry(`${YOOKASSA_API_URL}/payments/${paymentId}`, {
headers: { Authorization: getAuthHeader() },
})
if (!res.ok) {
const body = await res.json().catch(() => ({}))
throw new Error(`YooKassa getPayment error: ${res.status}${body.description || 'unknown'}`)
const data = await res.json()
return {
paymentId: data.id,
status: data.status,
confirmationUrl: data.confirmation?.confirmation_url || null,
expiresAt: data.expires_at || null,
paid: data.paid,
test: data.test,
}
return res.json()
}
const YOOKASSA_IP_RANGES_V4 = ['185.71.76.0/27', '185.71.77.0/27', '77.75.153.0/25', '77.75.154.128/25']
@@ -116,10 +123,12 @@ function isYookassaIp(ip) {
return YOOKASSA_IP_RANGES_V4.some((cidr) => cidrMatch(v4, cidr))
}
const TEST_MODE = process.env.YOOKASSA_SECRET_KEY?.startsWith('test_') ?? false
function isTestMode() {
return (process.env.YOOKASSA_SECRET_KEY?.startsWith('test_')) ?? false
}
export function validateWebhook(ip, body) {
if (!TEST_MODE && !isYookassaIp(ip)) {
if (!isTestMode() && !isYookassaIp(ip)) {
throw new Error('Invalid webhook source IP')
}
if (!body || typeof body !== 'object') {