style: format code biome
Local Build and Deploy / deploy (push) Failing after 46s

This commit is contained in:
openhands committed 2026-07-13 21:57:41 +02:00
1 parent 8efd032cc6
commit df38dccbf1
735 files changed
+128321 -120870

No files matched your search

+129 -111
View File
@@ -11,57 +11,66 @@
// carries `credits`, the in-game wallet), so a top-up credits the buyer's
// `credits` wallet via sendCurrency(), exactly like the voucher flow.
export const PAYPAL_API = process.env.PAYPAL_API?.replace(/\/+$/, "") ?? "https://api-m.sandbox.paypal.com";
export const PAYPAL_API =
process.env.PAYPAL_API?.replace(/\/+$/, "") ??
"https://api-m.sandbox.paypal.com";
export const PAYPAL_CURRENCY = (process.env.PAYPAL_CURRENCY ?? "USD").toUpperCase();
export const PAYPAL_CURRENCY = (
process.env.PAYPAL_CURRENCY ?? "USD"
).toUpperCase();
/** Credits granted per 1.00 of the order currency (configurable, sane default). */
export function creditsPerUnit(): number {
const n = Number(process.env.PAYPAL_CREDITS_PER_USD ?? "100");
return Number.isFinite(n) && n > 0 ? n : 100;
const n = Number(process.env.PAYPAL_CREDITS_PER_USD ?? "100");
return Number.isFinite(n) && n > 0 ? n : 100;
}
export class PayPalConfigError extends Error {}
function credentials(): { clientId: string; secret: string } {
const clientId = process.env.PAYPAL_CLIENT_ID;
const secret = process.env.PAYPAL_SECRET;
if (!clientId || !secret) {
throw new PayPalConfigError("PayPal is not configured. Set PAYPAL_CLIENT_ID and PAYPAL_SECRET.");
}
return { clientId, secret };
const clientId = process.env.PAYPAL_CLIENT_ID;
const secret = process.env.PAYPAL_SECRET;
if (!clientId || !secret) {
throw new PayPalConfigError(
"PayPal is not configured. Set PAYPAL_CLIENT_ID and PAYPAL_SECRET.",
);
}
return { clientId, secret };
}
/** True when both PayPal credentials are present. */
export function isPayPalConfigured(): boolean {
return Boolean(process.env.PAYPAL_CLIENT_ID && process.env.PAYPAL_SECRET);
return Boolean(process.env.PAYPAL_CLIENT_ID && process.env.PAYPAL_SECRET);
}
/** OAuth2 client-credentials token (short-lived; we fetch one per request). */
async function getAccessToken(): Promise<string> {
const { clientId, secret } = credentials();
const basic = Buffer.from(`${clientId}:${secret}`).toString("base64");
const res = await fetch(`${PAYPAL_API}/v1/oauth2/token`, {
method: "POST",
headers: {
Authorization: `Basic ${basic}`,
"Content-Type": "application/x-www-form-urlencoded",
},
body: "grant_type=client_credentials",
cache: "no-store",
});
if (!res.ok) {
const body = await res.text().catch(() => "");
throw new Error(`PayPal auth failed (${res.status}): ${body.slice(0, 300)}`);
}
const json = (await res.json()) as { access_token?: string };
if (!json.access_token) throw new Error("PayPal auth returned no access_token.");
return json.access_token;
const { clientId, secret } = credentials();
const basic = Buffer.from(`${clientId}:${secret}`).toString("base64");
const res = await fetch(`${PAYPAL_API}/v1/oauth2/token`, {
method: "POST",
headers: {
Authorization: `Basic ${basic}`,
"Content-Type": "application/x-www-form-urlencoded",
},
body: "grant_type=client_credentials",
cache: "no-store",
});
if (!res.ok) {
const body = await res.text().catch(() => "");
throw new Error(
`PayPal auth failed (${res.status}): ${body.slice(0, 300)}`,
);
}
const json = (await res.json()) as { access_token?: string };
if (!json.access_token)
throw new Error("PayPal auth returned no access_token.");
return json.access_token;
}
export interface CreatedOrder {
id: string;
approveUrl: string | null;
id: string;
approveUrl: string | null;
}
/**
@@ -69,99 +78,108 @@ export interface CreatedOrder {
* order id and the payer approval URL (rel === "approve") to redirect to.
*/
export async function createOrder(
amount: number,
opts: { description?: string; returnUrl?: string; cancelUrl?: string } = {},
amount: number,
opts: { description?: string; returnUrl?: string; cancelUrl?: string } = {},
): Promise<CreatedOrder> {
const token = await getAccessToken();
const value = amount.toFixed(2);
const token = await getAccessToken();
const value = amount.toFixed(2);
const res = await fetch(`${PAYPAL_API}/v2/checkout/orders`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
cache: "no-store",
body: JSON.stringify({
intent: "CAPTURE",
purchase_units: [
{
amount: { currency_code: PAYPAL_CURRENCY, value },
description: opts.description?.slice(0, 127),
},
],
application_context: {
shipping_preference: "NO_SHIPPING",
user_action: "PAY_NOW",
...(opts.returnUrl ? { return_url: opts.returnUrl } : {}),
...(opts.cancelUrl ? { cancel_url: opts.cancelUrl } : {}),
},
}),
});
const res = await fetch(`${PAYPAL_API}/v2/checkout/orders`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
cache: "no-store",
body: JSON.stringify({
intent: "CAPTURE",
purchase_units: [
{
amount: { currency_code: PAYPAL_CURRENCY, value },
description: opts.description?.slice(0, 127),
},
],
application_context: {
shipping_preference: "NO_SHIPPING",
user_action: "PAY_NOW",
...(opts.returnUrl ? { return_url: opts.returnUrl } : {}),
...(opts.cancelUrl ? { cancel_url: opts.cancelUrl } : {}),
},
}),
});
if (!res.ok) {
const body = await res.text().catch(() => "");
throw new Error(`PayPal create order failed (${res.status}): ${body.slice(0, 300)}`);
}
if (!res.ok) {
const body = await res.text().catch(() => "");
throw new Error(
`PayPal create order failed (${res.status}): ${body.slice(0, 300)}`,
);
}
const json = (await res.json()) as {
id: string;
links?: { rel: string; href: string }[];
};
const approveUrl = json.links?.find((l) => l.rel === "approve" || l.rel === "payer-action")?.href ?? null;
return { id: json.id, approveUrl };
const json = (await res.json()) as {
id: string;
links?: { rel: string; href: string }[];
};
const approveUrl =
json.links?.find((l) => l.rel === "approve" || l.rel === "payer-action")
?.href ?? null;
return { id: json.id, approveUrl };
}
export interface CaptureResult {
id: string;
status: string;
amount: number;
currency: string;
captureId: string | null;
payerEmail: string | null;
id: string;
status: string;
amount: number;
currency: string;
captureId: string | null;
payerEmail: string | null;
}
/** Capture a previously-approved order id. */
export async function captureOrder(orderId: string): Promise<CaptureResult> {
const token = await getAccessToken();
const res = await fetch(`${PAYPAL_API}/v2/checkout/orders/${encodeURIComponent(orderId)}/capture`, {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
cache: "no-store",
});
const token = await getAccessToken();
const res = await fetch(
`${PAYPAL_API}/v2/checkout/orders/${encodeURIComponent(orderId)}/capture`,
{
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
cache: "no-store",
},
);
if (!res.ok) {
const body = await res.text().catch(() => "");
throw new Error(`PayPal capture failed (${res.status}): ${body.slice(0, 300)}`);
}
if (!res.ok) {
const body = await res.text().catch(() => "");
throw new Error(
`PayPal capture failed (${res.status}): ${body.slice(0, 300)}`,
);
}
const json = (await res.json()) as {
id: string;
status: string;
payer?: { email_address?: string };
purchase_units?: {
payments?: {
captures?: {
id: string;
amount?: { value?: string; currency_code?: string };
}[];
};
}[];
};
const json = (await res.json()) as {
id: string;
status: string;
payer?: { email_address?: string };
purchase_units?: {
payments?: {
captures?: {
id: string;
amount?: { value?: string; currency_code?: string };
}[];
};
}[];
};
const capture = json.purchase_units?.[0]?.payments?.captures?.[0];
const amount = capture?.amount?.value ? Number(capture.amount.value) : 0;
const currency = capture?.amount?.currency_code ?? PAYPAL_CURRENCY;
const capture = json.purchase_units?.[0]?.payments?.captures?.[0];
const amount = capture?.amount?.value ? Number(capture.amount.value) : 0;
const currency = capture?.amount?.currency_code ?? PAYPAL_CURRENCY;
return {
id: json.id,
status: json.status,
amount,
currency,
captureId: capture?.id ?? null,
payerEmail: json.payer?.email_address ?? null,
};
return {
id: json.id,
status: json.status,
amount,
currency,
captureId: capture?.id ?? null,
payerEmail: json.payer?.email_address ?? null,
};
}