import { randomUUID } from "crypto";
import { ProfyApp, InsufficientBalance, AuthExpired, ProfyApiError } from "@profy-ai/sdk";
const profy = new ProfyApp({
clientId: process.env.PROFY_APP_ID!,
clientSecret: process.env.PROFY_APP_SECRET!,
onTokenRefresh: (newToken) => saveToDatabase(newToken),
});
const PRICES: Record<string, number> = {
generate_report: 10,
export_pdf: 5,
generate_summary: 3,
};
interface ChargeResult {
success: true;
charged: number;
balance: number;
}
interface ChargeError {
success: false;
reason: "balance_insufficient" | "auth_expired" | "rate_limited" | "unknown";
}
async function chargeUser(
userId: string,
token: string,
action: string
): Promise<ChargeResult | ChargeError> {
const idempotencyKey = `${userId}-${action}-${randomUUID()}`;
for (let attempt = 0; attempt < 3; attempt++) {
try {
const result = await profy.reportEvent(action, {
token,
idempotencyKey,
metadata: { userId, action, attempt },
});
return {
success: true,
charged: result.charged,
balance: result.balance_remaining,
};
} catch (err) {
if (err instanceof InsufficientBalance) {
return { success: false, reason: "balance_insufficient" };
}
if (err instanceof AuthExpired) {
return { success: false, reason: "auth_expired" };
}
if (err instanceof ProfyApiError && err.statusCode === 429) {
await new Promise((r) => setTimeout(r, 2 ** attempt * 1000));
continue;
}
return { success: false, reason: "unknown" };
}
}
return { success: false, reason: "rate_limited" };
}
async function handleGenerateReport(userId: string, token: string) {
const balance = await profy.getBalance(token);
if (balance.credits < PRICES.generate_report) {
return { error: "余额不足,请充值后再试" };
}
const report = await generateReportContent(userId);
const charge = await chargeUser(userId, token, "generate_report");
if (!charge.success) {
return { error: `扣费失败: ${charge.reason}` };
}
return { report, charged: charge.charged, balance: charge.balance };
}