fix: add retry to getPayment, normalize return, env validation, webhook/builder tests
This commit is contained in:
@@ -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') {
|
||||
|
||||
Reference in New Issue
Block a user