111 lines
4.0 KiB
JavaScript
111 lines
4.0 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.createOrder = createOrder;
|
|
exports.captureOrder = captureOrder;
|
|
exports.refundCapture = refundCapture;
|
|
exports.verifyWebhookEvent = verifyWebhookEvent;
|
|
exports.isConfigured = isConfigured;
|
|
const BASE_URL = process.env.PAYPAL_BASE_URL ?? 'https://api-m.paypal.com';
|
|
const CLIENT_ID = process.env.PAYPAL_CLIENT_ID ?? '';
|
|
const CLIENT_SECRET = process.env.PAYPAL_CLIENT_SECRET ?? '';
|
|
let cachedToken = null;
|
|
async function getAccessToken() {
|
|
if (cachedToken && Date.now() < cachedToken.expiresAt - 30_000) {
|
|
return cachedToken.token;
|
|
}
|
|
const res = await fetch(`${BASE_URL}/v1/oauth2/token`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
Authorization: `Basic ${Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString('base64')}`,
|
|
},
|
|
body: 'grant_type=client_credentials',
|
|
});
|
|
if (!res.ok)
|
|
throw new Error('PayPal: failed to obtain access token');
|
|
const json = await res.json();
|
|
cachedToken = { token: json.access_token, expiresAt: Date.now() + json.expires_in * 1000 };
|
|
return cachedToken.token;
|
|
}
|
|
async function ppFetch(path, init) {
|
|
const token = await getAccessToken();
|
|
const res = await fetch(`${BASE_URL}${path}`, {
|
|
...init,
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
Authorization: `Bearer ${token}`,
|
|
...(init?.headers ?? {}),
|
|
},
|
|
});
|
|
if (!res.ok) {
|
|
const err = await res.json().catch(() => ({}));
|
|
throw new Error(`PayPal ${path} failed: ${err?.message ?? res.statusText}`);
|
|
}
|
|
return res.json();
|
|
}
|
|
async function createOrder(params) {
|
|
const json = await ppFetch('/v2/checkout/orders', {
|
|
method: 'POST',
|
|
body: JSON.stringify({
|
|
intent: 'CAPTURE',
|
|
purchase_units: [
|
|
{
|
|
reference_id: params.orderId,
|
|
description: params.description,
|
|
amount: {
|
|
currency_code: params.currency,
|
|
value: (params.amount / 100).toFixed(2),
|
|
},
|
|
},
|
|
],
|
|
application_context: {
|
|
return_url: params.returnUrl,
|
|
cancel_url: params.cancelUrl,
|
|
brand_name: 'RentalDriveGo',
|
|
user_action: 'PAY_NOW',
|
|
},
|
|
}),
|
|
});
|
|
const approveLink = json.links?.find((l) => l.rel === 'approve');
|
|
return {
|
|
orderId: json.id,
|
|
approveUrl: approveLink?.href ?? '',
|
|
status: json.status,
|
|
};
|
|
}
|
|
async function captureOrder(paypalOrderId) {
|
|
return ppFetch(`/v2/checkout/orders/${paypalOrderId}/capture`, { method: 'POST', body: '{}' });
|
|
}
|
|
async function refundCapture(captureId, amount, currency, note) {
|
|
return ppFetch(`/v2/payments/captures/${captureId}/refund`, {
|
|
method: 'POST',
|
|
body: JSON.stringify({
|
|
amount: { currency_code: currency, value: (amount / 100).toFixed(2) },
|
|
note_to_payer: note,
|
|
}),
|
|
});
|
|
}
|
|
async function verifyWebhookEvent(headers, rawBody) {
|
|
try {
|
|
const json = await ppFetch('/v1/notifications/verify-webhook-signature', {
|
|
method: 'POST',
|
|
body: JSON.stringify({
|
|
auth_algo: headers['paypal-auth-algo'],
|
|
cert_url: headers['paypal-cert-url'],
|
|
transmission_id: headers['paypal-transmission-id'],
|
|
transmission_sig: headers['paypal-transmission-sig'],
|
|
transmission_time: headers['paypal-transmission-time'],
|
|
webhook_id: process.env.PAYPAL_WEBHOOK_ID ?? '',
|
|
webhook_event: JSON.parse(rawBody),
|
|
}),
|
|
});
|
|
return json.verification_status === 'SUCCESS';
|
|
}
|
|
catch {
|
|
return false;
|
|
}
|
|
}
|
|
function isConfigured() {
|
|
return !!(CLIENT_ID && CLIENT_SECRET && CLIENT_ID !== 'your-paypal-client-id');
|
|
}
|
|
//# sourceMappingURL=paypalService.js.map
|