mirror of
https://wget.la/https://github.com/leookun/cursor-byok
synced 2026-10-04 02:52:55 +08:00
fix(codex-auth): add reset card actions and tests
This commit is contained in:
@@ -12,8 +12,8 @@ import { buildResponsesBody } from "cursor-byok:protocol/openai-responses";
|
||||
import { codexProvider, isQuotaError } from "./provider.ts";
|
||||
import {
|
||||
accountIdentity,
|
||||
credentialDraft,
|
||||
consumeResetCardAction,
|
||||
credentialDraft,
|
||||
listResetCardsAction,
|
||||
parseCodexUsage,
|
||||
parseCredentialFiles,
|
||||
@@ -142,9 +142,113 @@ Deno.test("usage maps secondary to weekly and primary to five-hour quota", () =>
|
||||
assertEquals(quota.weekly?.remainingPercent, 75);
|
||||
assertEquals(quota.fiveHour?.remainingPercent, 20);
|
||||
assertEquals(quota.weekly?.resetAtMs, 1_900_000_000_000);
|
||||
assertEquals(quota.resetCreditsAvailable, 2);
|
||||
assertEquals(quotaState(quota, 1_700_000_000_000), { status: "ready" });
|
||||
});
|
||||
|
||||
Deno.test("reset card action lists safe card metadata and optional expiry", async () => {
|
||||
const result = await listResetCardsAction.run(
|
||||
snapshot({
|
||||
accessToken: "access-secret",
|
||||
accountId: "acct-1",
|
||||
refreshToken: null,
|
||||
displayName: "person@example.com",
|
||||
quota: null,
|
||||
}),
|
||||
null,
|
||||
context({
|
||||
fetch: (url, init) => {
|
||||
assertEquals(url, "https://chatgpt.com/backend-api/wham/rate-limit-reset-credits");
|
||||
assertEquals(init?.headers?.["ChatGPT-Account-Id"], "acct-1");
|
||||
return {
|
||||
status: 200,
|
||||
headers: {},
|
||||
body: JSON.stringify({
|
||||
available_count: 1,
|
||||
credits: [{
|
||||
id: "credit-1",
|
||||
reset_type: "codex_rate_limits",
|
||||
status: "available",
|
||||
granted_at: "2026-06-12T01:33:14Z",
|
||||
expires_at: "2026-07-12T01:33:14Z",
|
||||
title: "One free rate limit reset",
|
||||
}],
|
||||
}),
|
||||
};
|
||||
},
|
||||
}),
|
||||
);
|
||||
assertEquals(result.cards, [{
|
||||
id: "credit-1",
|
||||
title: "One free rate limit reset",
|
||||
status: "available",
|
||||
grantedAtMs: Date.parse("2026-06-12T01:33:14Z"),
|
||||
expiresAtMs: Date.parse("2026-07-12T01:33:14Z"),
|
||||
fields: [{
|
||||
id: "reset-type",
|
||||
label: { "en-US": "Reset type", "zh-CN": "重置类型" },
|
||||
value: "codex_rate_limits",
|
||||
}],
|
||||
}]);
|
||||
});
|
||||
|
||||
Deno.test("reset card action consumes a selected card and refreshes quota state", async () => {
|
||||
let requestNumber = 0;
|
||||
const result = await consumeResetCardAction.run(
|
||||
snapshot({
|
||||
accessToken: "access-secret",
|
||||
accountId: "acct-1",
|
||||
refreshToken: null,
|
||||
displayName: "person@example.com",
|
||||
quota: null,
|
||||
}),
|
||||
{ cardId: "credit-1" },
|
||||
context({
|
||||
fetch: (url, init) => {
|
||||
requestNumber += 1;
|
||||
if (requestNumber === 1 || requestNumber === 4) {
|
||||
assertEquals(url, "https://chatgpt.com/backend-api/wham/rate-limit-reset-credits");
|
||||
return {
|
||||
status: 200,
|
||||
headers: {},
|
||||
body: JSON.stringify(
|
||||
requestNumber === 1
|
||||
? { available_count: 1, credits: [{ id: "credit-1", status: "available" }] }
|
||||
: { available_count: 0, credits: [] },
|
||||
),
|
||||
};
|
||||
}
|
||||
if (requestNumber === 2) {
|
||||
assertEquals(
|
||||
url,
|
||||
"https://chatgpt.com/backend-api/wham/rate-limit-reset-credits/consume",
|
||||
);
|
||||
assertEquals(JSON.parse(init?.body ?? "{}"), {
|
||||
credit_id: "credit-1",
|
||||
redeem_request_id: JSON.parse(init?.body ?? "{}").redeem_request_id,
|
||||
});
|
||||
return { status: 200, headers: {}, body: JSON.stringify({ code: "reset" }) };
|
||||
}
|
||||
assertEquals(url, "https://chatgpt.com/backend-api/wham/usage");
|
||||
return {
|
||||
status: 200,
|
||||
headers: {},
|
||||
body: JSON.stringify({ rate_limit_reset_credits: { available_count: 0 } }),
|
||||
};
|
||||
},
|
||||
}),
|
||||
);
|
||||
assertEquals(requestNumber, 4);
|
||||
assertEquals(result.cards, []);
|
||||
const quota = (result.patch?.privateData as Record<string, unknown>).quota as Record<
|
||||
string,
|
||||
unknown
|
||||
>;
|
||||
assertEquals(quota.resetCreditsAvailable, 0);
|
||||
assertEquals(quota.weekly, null);
|
||||
assertEquals(quota.fiveHour, null);
|
||||
});
|
||||
|
||||
Deno.test("exhausted quota projects a cooling state until the latest reset", () => {
|
||||
const quota = parseCodexUsage({
|
||||
rate_limit: {
|
||||
|
||||
@@ -2,8 +2,8 @@ import { defineProviderPlugin } from "cursor-byok:plugin";
|
||||
import { codexDeviceOAuth } from "./oauth.ts";
|
||||
import { codexProvider } from "./provider.ts";
|
||||
import {
|
||||
credentialImport,
|
||||
consumeResetCardAction,
|
||||
credentialImport,
|
||||
listResetCardsAction,
|
||||
presentAccount,
|
||||
refreshAccount,
|
||||
|
||||
@@ -350,7 +350,9 @@ async function fetchResetCredits(
|
||||
const availableCount = number(root.available_count ?? root.availableCount);
|
||||
return {
|
||||
cards,
|
||||
availableCount: availableCount === null ? cards.filter((card) => card.status === "available").length : Math.max(0, Math.floor(availableCount)),
|
||||
availableCount: availableCount === null
|
||||
? cards.filter((card) => card.status === "available").length
|
||||
: Math.max(0, Math.floor(availableCount)),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -426,7 +428,10 @@ async function consumeResetCard(
|
||||
export const listResetCardsAction: ResourceAction = {
|
||||
id: LIST_RESET_CARDS_ACTION_ID,
|
||||
displayName: { "en-US": "View reset cards", "zh-CN": "查看重置卡" },
|
||||
description: { "en-US": "List available Codex reset cards.", "zh-CN": "查看当前账号的 Codex 重置卡。" },
|
||||
description: {
|
||||
"en-US": "List available Codex reset cards.",
|
||||
"zh-CN": "查看当前账号的 Codex 重置卡。",
|
||||
},
|
||||
target: "resource",
|
||||
run: listResetCards,
|
||||
};
|
||||
@@ -434,7 +439,10 @@ export const listResetCardsAction: ResourceAction = {
|
||||
export const consumeResetCardAction: ResourceAction = {
|
||||
id: CONSUME_RESET_CARD_ACTION_ID,
|
||||
displayName: { "en-US": "Use reset card", "zh-CN": "使用重置卡" },
|
||||
description: { "en-US": "Redeem one available Codex reset card.", "zh-CN": "消耗一张可用的 Codex 重置卡。" },
|
||||
description: {
|
||||
"en-US": "Redeem one available Codex reset card.",
|
||||
"zh-CN": "消耗一张可用的 Codex 重置卡。",
|
||||
},
|
||||
target: "card",
|
||||
destructive: true,
|
||||
run: consumeResetCard,
|
||||
|
||||
@@ -142,9 +142,7 @@ async function dispatch(message: { id: string; method: string; params?: JsonValu
|
||||
case "oauth.begin": {
|
||||
const support = resourceSupport(params.resourceType);
|
||||
const method = addMethod(support, params.methodId);
|
||||
result = method.type === "oauth2.authorization-code"
|
||||
? await method.begin(params.authorization as never, context)
|
||||
: await method.begin(context);
|
||||
result = method.type === "oauth2.authorization-code" ? await method.begin(params.authorization as never, context) : await method.begin(context);
|
||||
break;
|
||||
}
|
||||
case "oauth.poll": {
|
||||
|
||||
Reference in New Issue
Block a user