This allows us to identify which Dyad Pro user filed an issue on GitHub by using a partial internal identifier <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Adds a redacted Dyad Pro user ID (last 4 chars) to bug report/session templates, sourced from the Pro user info endpoint and exposed via user budget info. > > - **Frontend (HelpDialog)**: > - Display `Pro User ID` in prefilled bug report and session report bodies using `userBudget.redactedUserId`. > - Consume `useUserBudgetInfo` to access `userBudget`. > - **IPC/Backend**: > - `get-user-budget`: derive `redactedUserId` from `user_info.user_id` (mask all but last 4 chars); include in test mock and response. > - **Types**: > - Extend `UserBudgetInfoSchema` with `redactedUserId: string`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 1883a1ef94fec25b370df3d46054fb56d659dee8. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Adds a redacted Dyad Pro user ID (last 4 chars) to bug report templates to help correlate GitHub issues with Pro accounts while protecting privacy. - **New Features** - Derives redactedUserId from user_info.user_id in the Pro IPC handler and adds it to UserBudgetInfo. - Shows “Pro User ID” in HelpDialog’s debug info and session details. - Extends UserBudgetInfo schema with a redactedUserId field. <sup>Written for commit 1883a1ef94fec25b370df3d46054fb56d659dee8. Summary will update automatically on new commits.</sup> <!-- End of auto-generated description by cubic. -->
81 lines
2.8 KiB
TypeScript
81 lines
2.8 KiB
TypeScript
import fetch from "node-fetch"; // Electron main process might need node-fetch
|
|
import log from "electron-log";
|
|
import { createLoggedHandler } from "./safe_handle";
|
|
import { readSettings } from "../../main/settings"; // Assuming settings are read this way
|
|
import { UserBudgetInfo, UserBudgetInfoSchema } from "../ipc_types";
|
|
import { IS_TEST_BUILD } from "../utils/test_utils";
|
|
|
|
const logger = log.scope("pro_handlers");
|
|
const handle = createLoggedHandler(logger);
|
|
|
|
const CONVERSION_RATIO = (10 * 3) / 2;
|
|
|
|
export function registerProHandlers() {
|
|
// This method should try to avoid throwing errors because this is auxiliary
|
|
// information and isn't critical to using the app
|
|
handle("get-user-budget", async (): Promise<UserBudgetInfo | null> => {
|
|
if (IS_TEST_BUILD) {
|
|
// Return mock budget data for E2E tests instead of spamming the API
|
|
const resetDate = new Date();
|
|
resetDate.setDate(resetDate.getDate() + 30); // Reset in 30 days
|
|
return {
|
|
usedCredits: 100,
|
|
totalCredits: 1000,
|
|
budgetResetDate: resetDate,
|
|
redactedUserId: "<redacted-user-id-testing>",
|
|
};
|
|
}
|
|
logger.info("Attempting to fetch user budget information.");
|
|
|
|
const settings = readSettings();
|
|
|
|
const apiKey = settings.providerSettings?.auto?.apiKey?.value;
|
|
|
|
if (!apiKey) {
|
|
logger.error("LLM Gateway API key (Dyad Pro) is not configured.");
|
|
return null;
|
|
}
|
|
|
|
const url = "https://llm-gateway.dyad.sh/user/info";
|
|
const headers = {
|
|
"Content-Type": "application/json",
|
|
Authorization: `Bearer ${apiKey}`,
|
|
};
|
|
|
|
try {
|
|
// Use native fetch if available, otherwise node-fetch will be used via import
|
|
const response = await fetch(url, {
|
|
method: "GET",
|
|
headers: headers,
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const errorBody = await response.text();
|
|
logger.error(
|
|
`Failed to fetch user budget. Status: ${response.status}. Body: ${errorBody}`,
|
|
);
|
|
return null;
|
|
}
|
|
|
|
const data = await response.json();
|
|
const userInfoData = data["user_info"];
|
|
const userId = userInfoData["user_id"];
|
|
// Turn user_abc1234 => "****1234"
|
|
// Preserve the last 4 characters so we can correlate bug reports
|
|
// with the user.
|
|
const redactedUserId =
|
|
userId.length > 8 ? "****" + userId.slice(-4) : "<redacted>";
|
|
logger.info("Successfully fetched user budget information.");
|
|
return UserBudgetInfoSchema.parse({
|
|
usedCredits: userInfoData["spend"] * CONVERSION_RATIO,
|
|
totalCredits: userInfoData["max_budget"] * CONVERSION_RATIO,
|
|
budgetResetDate: new Date(userInfoData["budget_reset_at"]),
|
|
redactedUserId: redactedUserId,
|
|
});
|
|
} catch (error: any) {
|
|
logger.error(`Error fetching user budget: ${error.message}`, error);
|
|
return null;
|
|
}
|
|
});
|
|
}
|