omnigateway 0.12.12 → 0.12.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/bin/omni.js +378 -21
- package/gateway.js +346 -13
- package/package.json +1 -1
- package/public/assets/{Chip-D4qvhu1D.js → Chip-D0XSbQUr.js} +1 -1
- package/public/assets/{CopyValue-SnsT2LML.js → CopyValue-DAlmkISB.js} +3 -3
- package/public/assets/{Field-BYBri2NV.js → Field-DG1317zr.js} +1 -1
- package/public/assets/Lamp-Dk9XrTCg.js +26 -0
- package/public/assets/{Panel-CWmOTDAP.js → Panel-CsovmtxF.js} +23 -4
- package/public/assets/Rack-CDUOJkS2.js +483 -0
- package/public/assets/{Readout-BTh732hP.js → Readout-DlT5oxGO.js} +1 -1
- package/public/assets/RequestTable-i3TtCB9m.js +93 -0
- package/public/assets/{SummaryDeck-7ivuca39.js → SummaryDeck-DrzTQQo5.js} +2 -2
- package/public/assets/{Toggle-t82IhqEt.js → Toggle-CdMD58sy.js} +1 -1
- package/public/assets/{TokenBreakdown-D1Wtza1y.js → TokenBreakdown-BC6nqo1v.js} +1 -1
- package/public/assets/{WindowChart-BeGPsccS.js → WindowChart-Bqbl-KFO.js} +2 -2
- package/public/assets/_app-CSru2YTE.js +1 -0
- package/public/assets/_app.accounts-B2lQkMb0.js +70 -0
- package/public/assets/_app.console-a2TJDoBC.js +24 -0
- package/public/assets/_app.database-CqSoTi2l.js +24 -0
- package/public/assets/_app.index-BV1kJJjA.js +67 -0
- package/public/assets/_app.keys-Dq5O0AG9.js +92 -0
- package/public/assets/_app.logs-PjRK5wqy.js +46 -0
- package/public/assets/_app.models-BfmeeB5e.js +148 -0
- package/public/assets/_app.plugins._pluginId-Owb05aFv.js +20 -0
- package/public/assets/{_app.settings-C3GzeJ4q.js → _app.settings-5i-vvT-H.js} +7 -7
- package/public/assets/_app.usage--5qFtU1W.js +76 -0
- package/public/assets/chevron-down-Bb5ZGvwk.js +1 -0
- package/public/assets/chevron-right-hwF5mD6-.js +1 -0
- package/public/assets/{client-k1tkFSNH.js → client-BcXc3lek.js} +4 -4
- package/public/assets/{dist-D03q-60i.js → dist-BBGxva0Y.js} +1 -1
- package/public/assets/index-D1RDaq3l.js +14 -0
- package/public/assets/{login-DW2Ipp21.js → login-GB0ZGUvA.js} +4 -4
- package/public/assets/plus-BgcHxxIr.js +1 -0
- package/public/assets/{preload-helper-BPaHpbO_.js → preload-helper-B7KDmXJ9.js} +1 -1
- package/public/assets/rotate-ccw-Do43Argv.js +1 -0
- package/public/assets/{shared-Dtkw6SE0.js → shared-DDpLUhCp.js} +2 -2
- package/public/assets/{trash-D4QWzEK_.js → trash-00950_yY.js} +1 -1
- package/public/index.html +5 -5
- package/public/assets/Lamp-DkvXKB-B.js +0 -26
- package/public/assets/Rack-CEuCdVXc.js +0 -483
- package/public/assets/RequestTable-D8L6iVJV.js +0 -93
- package/public/assets/_app-Drf03PWk.js +0 -1
- package/public/assets/_app.accounts-W1USUo2Q.js +0 -70
- package/public/assets/_app.console-Co9d2ZiD.js +0 -44
- package/public/assets/_app.database-CtFJLcfE.js +0 -24
- package/public/assets/_app.index-DigYfob3.js +0 -67
- package/public/assets/_app.keys-B1fRMyU-.js +0 -92
- package/public/assets/_app.logs-CFixPsUw.js +0 -60
- package/public/assets/_app.models-Dpl1O2RE.js +0 -148
- package/public/assets/_app.plugins._pluginId-BK0ADugW.js +0 -20
- package/public/assets/_app.usage-D2qlcEp4.js +0 -76
- package/public/assets/chevron-down-Bs0tSOyA.js +0 -1
- package/public/assets/chevron-right-DSaI1kFo.js +0 -1
- package/public/assets/index-Bk9sabex.js +0 -14
- package/public/assets/plus-BCfjC6nk.js +0 -1
package/README.md
CHANGED
|
@@ -251,6 +251,7 @@ Use `--db <path>` to point one command somewhere else.
|
|
|
251
251
|
| `omni usage` | spend and tokens, by provider, model, key, or day |
|
|
252
252
|
| `omni quota` | provider quota per window: use, burn rate, and when it runs out |
|
|
253
253
|
| `omni quota refresh <id> \| --all` | read provider quota now, without waiting for the next poll |
|
|
254
|
+
| `omni quota resets <id>` / `omni quota reset <id>` | list / spend a banked Codex or Claude quota reset (irreversible) |
|
|
254
255
|
| `omni connect <provider>` | authorize an account from the terminal |
|
|
255
256
|
| `omni credentials …` | list, show, enable, disable, `set`, `rm`, refresh, `add-key`, health |
|
|
256
257
|
| `omni models …` | list, show, put, `rm`, `dry-run`, `catalog` |
|
package/bin/omni.js
CHANGED
|
@@ -24739,12 +24739,18 @@ var ANTHROPIC_MODELS = {
|
|
|
24739
24739
|
};
|
|
24740
24740
|
var ONE_M_SUFFIX = "[1m]";
|
|
24741
24741
|
var DATED_SUFFIX = /-\d{8}$/;
|
|
24742
|
-
function
|
|
24742
|
+
function anthropicChoice(model) {
|
|
24743
24743
|
let id = model.trim();
|
|
24744
24744
|
if (id.toLowerCase().endsWith(ONE_M_SUFFIX))
|
|
24745
24745
|
id = id.slice(0, -ONE_M_SUFFIX.length).trim();
|
|
24746
24746
|
id = id.replace(DATED_SUFFIX, "");
|
|
24747
|
-
return ANTHROPIC_MODELS.models.find((m) => m.id === id)
|
|
24747
|
+
return ANTHROPIC_MODELS.models.find((m) => m.id === id);
|
|
24748
|
+
}
|
|
24749
|
+
function anthropicReasoningForm(model) {
|
|
24750
|
+
return anthropicChoice(model)?.reasoningForm ?? "adaptive";
|
|
24751
|
+
}
|
|
24752
|
+
function anthropicMaxOutputTokens(model) {
|
|
24753
|
+
return anthropicChoice(model)?.limits.maxOutputTokens;
|
|
24748
24754
|
}
|
|
24749
24755
|
|
|
24750
24756
|
// packages/providers/src/anthropic/descriptor.ts
|
|
@@ -25635,7 +25641,8 @@ function codecAdapter(id, capabilities2, codec2, origins) {
|
|
|
25635
25641
|
credentials: req.credentials,
|
|
25636
25642
|
fail,
|
|
25637
25643
|
...req.requestId === undefined ? {} : { requestId: req.requestId },
|
|
25638
|
-
...req.autoCache === undefined ? {} : { autoCacheEnabled: req.autoCache }
|
|
25644
|
+
...req.autoCache === undefined ? {} : { autoCacheEnabled: req.autoCache },
|
|
25645
|
+
...req.maxOutputTokens === undefined ? {} : { maxOutputTokens: req.maxOutputTokens }
|
|
25639
25646
|
}));
|
|
25640
25647
|
const described = built?.request ?? {};
|
|
25641
25648
|
const request2 = {
|
|
@@ -27340,6 +27347,12 @@ function addAutoCacheBreakpoints(body, req, note2) {
|
|
|
27340
27347
|
lastHistory.cache_control = { type: "ephemeral" };
|
|
27341
27348
|
note2("anthropic:history-cache-breakpoint-added");
|
|
27342
27349
|
}
|
|
27350
|
+
function defaultMaxTokens(model, saved) {
|
|
27351
|
+
const ceiling = anthropicMaxOutputTokens(model);
|
|
27352
|
+
if (saved === undefined)
|
|
27353
|
+
return ceiling ?? 4096;
|
|
27354
|
+
return ceiling === undefined ? saved : Math.min(saved, ceiling);
|
|
27355
|
+
}
|
|
27343
27356
|
function toWire(req, model, opts) {
|
|
27344
27357
|
const cloak = opts.cloak ?? null;
|
|
27345
27358
|
const degradations = [];
|
|
@@ -27386,7 +27399,7 @@ function toWire(req, model, opts) {
|
|
|
27386
27399
|
}
|
|
27387
27400
|
return [{ role: m.role, content: encodeSystemTurn(m.content, cloak) }];
|
|
27388
27401
|
}),
|
|
27389
|
-
max_tokens: req.maxTokens ??
|
|
27402
|
+
max_tokens: req.maxTokens ?? defaultMaxTokens(model, opts.maxOutputTokens),
|
|
27390
27403
|
stream: req.stream
|
|
27391
27404
|
};
|
|
27392
27405
|
if (systemCache.retarget !== undefined) {
|
|
@@ -27525,7 +27538,8 @@ var anthropicCodec = {
|
|
|
27525
27538
|
const { body, degradations } = toWire(input2.request, input2.model, {
|
|
27526
27539
|
oauth,
|
|
27527
27540
|
cloak,
|
|
27528
|
-
autoCache: input2.autoCacheEnabled === true
|
|
27541
|
+
autoCache: input2.autoCacheEnabled === true,
|
|
27542
|
+
...input2.maxOutputTokens === undefined ? {} : { maxOutputTokens: input2.maxOutputTokens }
|
|
27529
27543
|
});
|
|
27530
27544
|
const firstUser = input2.request.messages.find((m) => m.role === "user");
|
|
27531
27545
|
const firstText = firstUser?.content.find((b) => b.type === "text");
|
|
@@ -27858,8 +27872,125 @@ var anthropicOAuthFlow = {
|
|
|
27858
27872
|
if (!usageReadable(res.status, "anthropic"))
|
|
27859
27873
|
return null;
|
|
27860
27874
|
return parseAnthropicUsage(parsed(res.body), now());
|
|
27875
|
+
},
|
|
27876
|
+
async* resetCredits({ secrets }) {
|
|
27877
|
+
if (secrets.accessToken === null)
|
|
27878
|
+
return null;
|
|
27879
|
+
const res = yield getJsonRequest(RESET_STATUS_URL, anthropicProfile, {
|
|
27880
|
+
accessToken: secrets.accessToken,
|
|
27881
|
+
extraHeaders: SIDE_HEADERS
|
|
27882
|
+
});
|
|
27883
|
+
if (!usageReadable(res.status, "anthropic"))
|
|
27884
|
+
return null;
|
|
27885
|
+
const root = recordOf(parsed(res.body));
|
|
27886
|
+
return root === null ? null : parseResetGrants(root.cedar_ember ?? null);
|
|
27887
|
+
},
|
|
27888
|
+
async* redeemReset({ secrets, creditId, requestId, fail }) {
|
|
27889
|
+
if (secrets.accessToken === null)
|
|
27890
|
+
throw fail("AUTH", "credential holds no access token");
|
|
27891
|
+
const grantId = grantOf(creditId);
|
|
27892
|
+
if (grantId === null)
|
|
27893
|
+
throw fail("CONFLICT", "that reset credit is not available");
|
|
27894
|
+
const profile = yield getJsonRequest(PROFILE_URL, anthropicProfile, {
|
|
27895
|
+
accessToken: secrets.accessToken,
|
|
27896
|
+
extraHeaders: SIDE_HEADERS
|
|
27897
|
+
});
|
|
27898
|
+
if (profile.status < 200 || profile.status >= 300) {
|
|
27899
|
+
throw fail(redeemErrorCode(profile.status), `profile read refused: http_${profile.status}`, {
|
|
27900
|
+
status: profile.status
|
|
27901
|
+
});
|
|
27902
|
+
}
|
|
27903
|
+
const orgId = orgIdOf(parsed(profile.body));
|
|
27904
|
+
if (orgId === null)
|
|
27905
|
+
throw fail("UPSTREAM", "profile names no organization");
|
|
27906
|
+
const res = yield postJsonRequest(`https://api.anthropic.com/api/organizations/${orgId}/reset_rate_limits`, anthropicProfile, {
|
|
27907
|
+
contentType: "application/json",
|
|
27908
|
+
body: JSON.stringify({ program: RESET_PROGRAM, grant_id: grantId, request_id: requestId }),
|
|
27909
|
+
extraHeaders: [["Authorization", `Bearer ${secrets.accessToken}`], ...SIDE_HEADERS]
|
|
27910
|
+
});
|
|
27911
|
+
if (res.status < 200 || res.status >= 300) {
|
|
27912
|
+
throw fail(redeemErrorCode(res.status), `reset claim refused: http_${res.status}`, {
|
|
27913
|
+
status: res.status
|
|
27914
|
+
});
|
|
27915
|
+
}
|
|
27916
|
+
return claimOutcome(parsed(res.body), fail);
|
|
27861
27917
|
}
|
|
27862
27918
|
};
|
|
27919
|
+
var RESET_PROGRAM = "cedar_ember";
|
|
27920
|
+
var RESET_STATUS_URL = `${USAGE_URL}?cedar_ember=1&skip_spend=1`;
|
|
27921
|
+
var PROFILE_URL = "https://api.anthropic.com/api/oauth/profile";
|
|
27922
|
+
var ORG_ID = /^[A-Za-z0-9-]{1,64}$/;
|
|
27923
|
+
var SIDE_HEADERS = [["anthropic-beta", "oauth-2025-04-20"]];
|
|
27924
|
+
var USE_SUFFIX = /-u(\d+)$/;
|
|
27925
|
+
function creditIdOf(grantId, left) {
|
|
27926
|
+
return `${grantId}-u${left}`;
|
|
27927
|
+
}
|
|
27928
|
+
function grantOf(creditId) {
|
|
27929
|
+
const grant = creditId.replace(USE_SUFFIX, "");
|
|
27930
|
+
return grant === creditId || grant === "" ? null : grant;
|
|
27931
|
+
}
|
|
27932
|
+
function orgIdOf(value) {
|
|
27933
|
+
const org = recordOf(recordOf(value)?.organization);
|
|
27934
|
+
const uuid3 = org?.uuid;
|
|
27935
|
+
return typeof uuid3 === "string" && ORG_ID.test(uuid3) ? uuid3 : null;
|
|
27936
|
+
}
|
|
27937
|
+
function parseResetGrants(value) {
|
|
27938
|
+
if (value === null)
|
|
27939
|
+
return { available: 0, credits: [] };
|
|
27940
|
+
const block = recordOf(value);
|
|
27941
|
+
if (block === null || !Array.isArray(block.grants))
|
|
27942
|
+
return null;
|
|
27943
|
+
const next = typeof block.next_grant_id === "string" ? block.next_grant_id : null;
|
|
27944
|
+
const atLimit = block.at_limit === true;
|
|
27945
|
+
let available = 0;
|
|
27946
|
+
const credits = block.grants.flatMap((raw) => {
|
|
27947
|
+
const g = recordOf(raw);
|
|
27948
|
+
if (g === null || typeof g.id !== "string")
|
|
27949
|
+
return [];
|
|
27950
|
+
const left = typeof g.resets_left === "number" ? g.resets_left : 0;
|
|
27951
|
+
const claimable = left > 0 && g.usable_now === true && g.paused !== true && (g.use_requires_limit !== true || atLimit) && (next === null || next === g.id);
|
|
27952
|
+
if (claimable)
|
|
27953
|
+
available += left;
|
|
27954
|
+
return [
|
|
27955
|
+
{
|
|
27956
|
+
id: creditIdOf(g.id, left),
|
|
27957
|
+
status: claimable ? "available" : left > 0 ? "unavailable" : "used",
|
|
27958
|
+
title: typeof g.label === "string" && g.label !== "" ? g.label : null,
|
|
27959
|
+
grantedAt: isoOrNull(g.starts_at),
|
|
27960
|
+
expiresAt: isoOrNull(g.ends_at)
|
|
27961
|
+
}
|
|
27962
|
+
];
|
|
27963
|
+
});
|
|
27964
|
+
return { available, credits };
|
|
27965
|
+
}
|
|
27966
|
+
function claimOutcome(value, fail) {
|
|
27967
|
+
const body = recordOf(value);
|
|
27968
|
+
const result = typeof body?.result === "string" ? body.result : null;
|
|
27969
|
+
if (result === "reset") {
|
|
27970
|
+
return { windowsReset: Array.isArray(body?.cleared) ? body.cleared.length : null };
|
|
27971
|
+
}
|
|
27972
|
+
if (result === "cooldown")
|
|
27973
|
+
throw fail("RATE_LIMIT", "reset claim refused: cooldown");
|
|
27974
|
+
if (result === "already_used" || result === "not_limited" || result === "ineligible") {
|
|
27975
|
+
throw fail("CONFLICT", `reset claim refused: ${result}`);
|
|
27976
|
+
}
|
|
27977
|
+
throw fail("UPSTREAM", "reset claim answered without a reset");
|
|
27978
|
+
}
|
|
27979
|
+
function redeemErrorCode(status) {
|
|
27980
|
+
if (status === 429)
|
|
27981
|
+
return "RATE_LIMIT";
|
|
27982
|
+
if (status === 401 || status === 403)
|
|
27983
|
+
return "AUTH";
|
|
27984
|
+
if (status >= 400 && status < 500)
|
|
27985
|
+
return "CONFLICT";
|
|
27986
|
+
return "UPSTREAM";
|
|
27987
|
+
}
|
|
27988
|
+
function isoOrNull(value) {
|
|
27989
|
+
if (typeof value !== "string")
|
|
27990
|
+
return null;
|
|
27991
|
+
const at = Date.parse(value);
|
|
27992
|
+
return Number.isNaN(at) ? null : at;
|
|
27993
|
+
}
|
|
27863
27994
|
// packages/providers/src/antigravity/codec.ts
|
|
27864
27995
|
import { createHash as createHash2 } from "crypto";
|
|
27865
27996
|
|
|
@@ -29181,7 +29312,7 @@ var grokOAuthFlow = {
|
|
|
29181
29312
|
|
|
29182
29313
|
// packages/providers/src/kilo/oauth.ts
|
|
29183
29314
|
var CODES_URL = "https://api.kilo.ai/api/device-auth/codes";
|
|
29184
|
-
var
|
|
29315
|
+
var PROFILE_URL2 = "https://api.kilo.ai/api/profile";
|
|
29185
29316
|
var FALLBACK_VERIFICATION_URL = "https://kilo.ai";
|
|
29186
29317
|
var DEFAULT_EXPIRES_SECONDS = 300;
|
|
29187
29318
|
var POLL_INTERVAL_SECONDS = 3;
|
|
@@ -29213,7 +29344,7 @@ function deviceCodeFrom(value, fail) {
|
|
|
29213
29344
|
}
|
|
29214
29345
|
async function* orgIdFor(accessToken) {
|
|
29215
29346
|
try {
|
|
29216
|
-
const res = yield getJsonRequest(
|
|
29347
|
+
const res = yield getJsonRequest(PROFILE_URL2, kiloProfile, { accessToken });
|
|
29217
29348
|
if (res.status < 200 || res.status >= 300)
|
|
29218
29349
|
return null;
|
|
29219
29350
|
const record2 = recordFrom(parsed(res.body));
|
|
@@ -29721,6 +29852,7 @@ var AUTHORIZE_URL3 = "https://auth.openai.com/oauth/authorize";
|
|
|
29721
29852
|
var TOKEN_URL5 = "https://auth.openai.com/oauth/token";
|
|
29722
29853
|
var SCOPES4 = "openid profile email offline_access";
|
|
29723
29854
|
var USAGE_URL3 = "https://chatgpt.com/backend-api/wham/usage";
|
|
29855
|
+
var RESET_CREDITS_URL = "https://chatgpt.com/backend-api/wham/rate-limit-reset-credits";
|
|
29724
29856
|
function isRecord7(value) {
|
|
29725
29857
|
return typeof value === "object" && value !== null;
|
|
29726
29858
|
}
|
|
@@ -29874,8 +30006,78 @@ var openaiOAuthFlow = {
|
|
|
29874
30006
|
if (!usageReadable(res.status, "openai"))
|
|
29875
30007
|
return null;
|
|
29876
30008
|
return parseOpenAIUsage(parsed(res.body), now());
|
|
30009
|
+
},
|
|
30010
|
+
async* resetCredits({ secrets, providerData }) {
|
|
30011
|
+
if (secrets.accessToken === null)
|
|
30012
|
+
return null;
|
|
30013
|
+
const res = yield getJsonRequest(RESET_CREDITS_URL, openaiProfile, {
|
|
30014
|
+
accessToken: secrets.accessToken,
|
|
30015
|
+
extraHeaders: accountHeader(providerData)
|
|
30016
|
+
});
|
|
30017
|
+
if (!usageReadable(res.status, "openai"))
|
|
30018
|
+
return null;
|
|
30019
|
+
return parseResetCredits(parsed(res.body));
|
|
30020
|
+
},
|
|
30021
|
+
async* redeemReset({ secrets, providerData, creditId, requestId, fail }) {
|
|
30022
|
+
if (secrets.accessToken === null)
|
|
30023
|
+
throw fail("AUTH", "credential holds no access token");
|
|
30024
|
+
const res = yield postJsonRequest(`${RESET_CREDITS_URL}/consume`, openaiProfile, {
|
|
30025
|
+
contentType: "application/json",
|
|
30026
|
+
body: JSON.stringify({ credit_id: creditId, redeem_request_id: requestId }),
|
|
30027
|
+
extraHeaders: [
|
|
30028
|
+
["Authorization", `Bearer ${secrets.accessToken}`],
|
|
30029
|
+
...accountHeader(providerData)
|
|
30030
|
+
]
|
|
30031
|
+
});
|
|
30032
|
+
if (res.status < 200 || res.status >= 300) {
|
|
30033
|
+
throw fail(redeemErrorCode2(res.status), `reset credit redeem refused: http_${res.status}`, {
|
|
30034
|
+
status: res.status
|
|
30035
|
+
});
|
|
30036
|
+
}
|
|
30037
|
+
const body = recordOf(parsed(res.body));
|
|
30038
|
+
const windowsReset = body === null ? null : numberOf(body, ["windows_reset"]);
|
|
30039
|
+
return { windowsReset };
|
|
29877
30040
|
}
|
|
29878
30041
|
};
|
|
30042
|
+
function accountHeader(providerData) {
|
|
30043
|
+
const accountId = accountIdFromProviderData(providerData);
|
|
30044
|
+
return accountId === null ? [] : [["chatgpt-account-id", accountId]];
|
|
30045
|
+
}
|
|
30046
|
+
function redeemErrorCode2(status) {
|
|
30047
|
+
if (status === 429)
|
|
30048
|
+
return "RATE_LIMIT";
|
|
30049
|
+
if (status === 401 || status === 403)
|
|
30050
|
+
return "AUTH";
|
|
30051
|
+
if (status >= 400 && status < 500)
|
|
30052
|
+
return "CONFLICT";
|
|
30053
|
+
return "UPSTREAM";
|
|
30054
|
+
}
|
|
30055
|
+
function isoOrNull2(value) {
|
|
30056
|
+
if (typeof value !== "string")
|
|
30057
|
+
return null;
|
|
30058
|
+
const at = Date.parse(value);
|
|
30059
|
+
return Number.isFinite(at) ? at : null;
|
|
30060
|
+
}
|
|
30061
|
+
function parseResetCredits(value) {
|
|
30062
|
+
const root = recordOf(value);
|
|
30063
|
+
if (root === null || !Array.isArray(root.credits))
|
|
30064
|
+
return null;
|
|
30065
|
+
const credits = root.credits.flatMap((raw) => {
|
|
30066
|
+
const c = recordOf(raw);
|
|
30067
|
+
if (c === null || typeof c.id !== "string" || typeof c.status !== "string")
|
|
30068
|
+
return [];
|
|
30069
|
+
return [
|
|
30070
|
+
{
|
|
30071
|
+
id: c.id,
|
|
30072
|
+
status: c.status,
|
|
30073
|
+
title: typeof c.title === "string" ? c.title : null,
|
|
30074
|
+
grantedAt: isoOrNull2(c.granted_at),
|
|
30075
|
+
expiresAt: isoOrNull2(c.expires_at)
|
|
30076
|
+
}
|
|
30077
|
+
];
|
|
30078
|
+
});
|
|
30079
|
+
return { available: credits.filter((c) => c.status === "available").length, credits };
|
|
30080
|
+
}
|
|
29879
30081
|
|
|
29880
30082
|
// packages/providers/src/builtinOAuth.ts
|
|
29881
30083
|
function builtinOAuthFlows() {
|
|
@@ -32806,6 +33008,11 @@ var quotaRefreshSchema = exports_external.discriminatedUnion("kind", [
|
|
|
32806
33008
|
}).strict(),
|
|
32807
33009
|
exports_external.object({ kind: exports_external.literal("all") }).strict()
|
|
32808
33010
|
]);
|
|
33011
|
+
var accountIdSchema = exports_external.string().trim().min(1).max(64).regex(/^[A-Za-z0-9_-]+$/, "credentialId must be an account id");
|
|
33012
|
+
var redeemResetSchema = exports_external.object({
|
|
33013
|
+
credentialId: accountIdSchema,
|
|
33014
|
+
creditId: exports_external.string().min(1).max(128).regex(/^[A-Za-z0-9_-]+$/).optional()
|
|
33015
|
+
}).strict();
|
|
32809
33016
|
var dimensionSchema = exports_external.enum([
|
|
32810
33017
|
"credential",
|
|
32811
33018
|
"model",
|
|
@@ -35215,6 +35422,29 @@ function oauthAdapter(id, flow, opts = {}) {
|
|
|
35215
35422
|
return Promise.resolve(null);
|
|
35216
35423
|
return runStep(id, "usage", step, deps, origins);
|
|
35217
35424
|
}
|
|
35425
|
+
},
|
|
35426
|
+
...flow.resetCredits === undefined ? {} : {
|
|
35427
|
+
resetCredits: (secrets, deps, providerData) => {
|
|
35428
|
+
const step = flow.resetCredits?.({ secrets, providerData, ...helpers(deps) });
|
|
35429
|
+
if (step === undefined)
|
|
35430
|
+
return Promise.resolve(null);
|
|
35431
|
+
return runStep(id, "resetCredits", step, deps, origins);
|
|
35432
|
+
}
|
|
35433
|
+
},
|
|
35434
|
+
...flow.redeemReset === undefined ? {} : {
|
|
35435
|
+
redeemReset: (secrets, deps, providerData, creditId, requestId) => {
|
|
35436
|
+
const step = flow.redeemReset?.({
|
|
35437
|
+
secrets,
|
|
35438
|
+
providerData,
|
|
35439
|
+
creditId,
|
|
35440
|
+
requestId,
|
|
35441
|
+
...helpers(deps)
|
|
35442
|
+
});
|
|
35443
|
+
if (step === undefined) {
|
|
35444
|
+
return Promise.reject(flowFailure(id, "redeemReset", "has no redeem step"));
|
|
35445
|
+
}
|
|
35446
|
+
return runStep(id, "redeemReset", step, deps, origins);
|
|
35447
|
+
}
|
|
35218
35448
|
}
|
|
35219
35449
|
};
|
|
35220
35450
|
if (flow.kind === "pkce")
|
|
@@ -35250,11 +35480,32 @@ function isAuthorizeStart(value) {
|
|
|
35250
35480
|
const candidate = value;
|
|
35251
35481
|
return typeof candidate.authorizeUrl === "string" && typeof candidate.pending === "object" && candidate.pending !== null;
|
|
35252
35482
|
}
|
|
35483
|
+
function isResetCreditsOrNull(value) {
|
|
35484
|
+
if (value === null)
|
|
35485
|
+
return true;
|
|
35486
|
+
if (typeof value !== "object")
|
|
35487
|
+
return false;
|
|
35488
|
+
const candidate = value;
|
|
35489
|
+
return typeof candidate.available === "number" && Array.isArray(candidate.credits) && candidate.credits.every((c) => {
|
|
35490
|
+
if (typeof c !== "object" || c === null)
|
|
35491
|
+
return false;
|
|
35492
|
+
const row = c;
|
|
35493
|
+
return typeof row.id === "string" && typeof row.status === "string" && (row.title === null || typeof row.title === "string") && (row.grantedAt === null || typeof row.grantedAt === "number") && (row.expiresAt === null || typeof row.expiresAt === "number");
|
|
35494
|
+
});
|
|
35495
|
+
}
|
|
35496
|
+
function isResetRedeemed(value) {
|
|
35497
|
+
if (typeof value !== "object" || value === null)
|
|
35498
|
+
return false;
|
|
35499
|
+
const held = value.windowsReset;
|
|
35500
|
+
return held === null || typeof held === "number";
|
|
35501
|
+
}
|
|
35253
35502
|
var RETURN_SHAPE = {
|
|
35254
35503
|
start: isAuthorizeStart,
|
|
35255
35504
|
begin: isAuthorizeStart,
|
|
35256
35505
|
exchange: isFlowResult,
|
|
35257
|
-
refresh: isFlowResult
|
|
35506
|
+
refresh: isFlowResult,
|
|
35507
|
+
resetCredits: isResetCreditsOrNull,
|
|
35508
|
+
redeemReset: isResetRedeemed
|
|
35258
35509
|
};
|
|
35259
35510
|
|
|
35260
35511
|
// packages/control/src/oauth/index.ts
|
|
@@ -35474,6 +35725,11 @@ function validateOAuthFlow(id, value) {
|
|
|
35474
35725
|
if (value.usage !== undefined) {
|
|
35475
35726
|
checkAt(typeof value.usage === "function", id, "oauth.usage", "a function");
|
|
35476
35727
|
}
|
|
35728
|
+
for (const fn of ["resetCredits", "redeemReset"]) {
|
|
35729
|
+
if (value[fn] !== undefined) {
|
|
35730
|
+
checkAt(typeof value[fn] === "function", id, `oauth.${fn}`, "a function");
|
|
35731
|
+
}
|
|
35732
|
+
}
|
|
35477
35733
|
if (kind === "device") {
|
|
35478
35734
|
checkAt(typeof value.begin === "function", id, "oauth.begin", "a function");
|
|
35479
35735
|
checkAt(typeof value.needsDeviceId === "boolean", id, "oauth.needsDeviceId", "a boolean");
|
|
@@ -35669,6 +35925,52 @@ async function quotaHistory(deps, input2) {
|
|
|
35669
35925
|
|
|
35670
35926
|
// packages/control/src/quota/clientHistory.ts
|
|
35671
35927
|
var MAX_SPAN_MS = 16 * 24 * 60 * 60 * 1000;
|
|
35928
|
+
// packages/control/src/quota/resets.ts
|
|
35929
|
+
async function resettable(deps, credentialId) {
|
|
35930
|
+
const credential = await deps.store.credentials.get(credentialId.trim());
|
|
35931
|
+
if (credential === null)
|
|
35932
|
+
throw new GatewayError("BAD_REQUEST", "no such credential");
|
|
35933
|
+
const provider = deps.providers[credential.provider];
|
|
35934
|
+
const list = provider?.resetCredits;
|
|
35935
|
+
const redeem = provider?.redeemReset;
|
|
35936
|
+
if (credential.authType !== "oauth" || list === undefined || redeem === undefined) {
|
|
35937
|
+
throw new GatewayError("BAD_REQUEST", "this account's provider has no quota resets");
|
|
35938
|
+
}
|
|
35939
|
+
return { credential, list, redeem };
|
|
35940
|
+
}
|
|
35941
|
+
async function listFor(deps, r) {
|
|
35942
|
+
const secrets = await usageSecretsFor(deps, r.credential);
|
|
35943
|
+
const read = await r.list(secrets, { http: deps.http, now: deps.now }, r.credential.providerData);
|
|
35944
|
+
if (read === null) {
|
|
35945
|
+
throw new GatewayError("UPSTREAM", "provider answered the reset list with nothing usable", {
|
|
35946
|
+
gatewayAuthored: true
|
|
35947
|
+
});
|
|
35948
|
+
}
|
|
35949
|
+
return read;
|
|
35950
|
+
}
|
|
35951
|
+
async function listResetCredits(deps, credentialId) {
|
|
35952
|
+
const r = await resettable(deps, credentialId);
|
|
35953
|
+
return { credentialId: r.credential.id, ...await listFor(deps, r) };
|
|
35954
|
+
}
|
|
35955
|
+
async function redeemResetCredit(deps, request2) {
|
|
35956
|
+
const r = await resettable(deps, request2.credentialId);
|
|
35957
|
+
return deps.coord.mutex.withLock(PROBE_LOCK_PREFIX + r.credential.id, PROBE_LOCK_TTL_MS, PROBE_LOCK_WAIT_MS, () => redeemLocked(deps, r, request2));
|
|
35958
|
+
}
|
|
35959
|
+
async function redeemLocked(deps, r, request2) {
|
|
35960
|
+
const available = (await listFor(deps, r)).credits.filter((c) => c.status === "available").sort((a, b) => (a.expiresAt ?? Number.POSITIVE_INFINITY) - (b.expiresAt ?? Number.POSITIVE_INFINITY));
|
|
35961
|
+
const credit = request2.creditId === undefined ? available[0] : available.find((c) => c.id === request2.creditId);
|
|
35962
|
+
if (credit === undefined) {
|
|
35963
|
+
throw new GatewayError("CONFLICT", request2.creditId === undefined ? "no reset credit is available for this account" : "that reset credit is not available");
|
|
35964
|
+
}
|
|
35965
|
+
const secrets = await usageSecretsFor(deps, r.credential);
|
|
35966
|
+
const { windowsReset } = await r.redeem(secrets, { http: deps.http, now: deps.now }, r.credential.providerData, credit.id, crypto.randomUUID());
|
|
35967
|
+
let quotaRefreshed = false;
|
|
35968
|
+
try {
|
|
35969
|
+
quotaRefreshed = await probe(deps, r.credential) !== null;
|
|
35970
|
+
} catch {}
|
|
35971
|
+
return { credentialId: r.credential.id, creditId: credit.id, windowsReset, quotaRefreshed };
|
|
35972
|
+
}
|
|
35973
|
+
|
|
35672
35974
|
// packages/control/src/quota/poll.ts
|
|
35673
35975
|
var CONCURRENCY = 4;
|
|
35674
35976
|
var RATE_LIMIT_COOLDOWN_MS = 180000;
|
|
@@ -35676,14 +35978,17 @@ var COOLDOWN_PREFIX = "quota:cooldown:";
|
|
|
35676
35978
|
var PROBE_LOCK_PREFIX = "quota:probe:";
|
|
35677
35979
|
var PROBE_LOCK_TTL_MS = 60000;
|
|
35678
35980
|
var PROBE_LOCK_WAIT_MS = 30000;
|
|
35981
|
+
async function usageSecretsFor(deps, credential) {
|
|
35982
|
+
const refreshed = credential.hasRefreshToken && credential.expiresAt !== null && credential.expiresAt - SCHEDULER_REFRESH_LEAD_MS <= deps.now() ? await deps.refresh(credential) : null;
|
|
35983
|
+
return refreshed === null ? await credential.openForUsage() : { accessToken: refreshed.accessToken };
|
|
35984
|
+
}
|
|
35679
35985
|
async function probe(deps, credential) {
|
|
35680
35986
|
if (credential.authType !== "oauth")
|
|
35681
35987
|
return null;
|
|
35682
35988
|
const provider = deps.providers[credential.provider];
|
|
35683
35989
|
if (provider?.usage === undefined)
|
|
35684
35990
|
return null;
|
|
35685
|
-
const
|
|
35686
|
-
const secrets = refreshed === null ? await credential.openForUsage() : { accessToken: refreshed.accessToken };
|
|
35991
|
+
const secrets = await usageSecretsFor(deps, credential);
|
|
35687
35992
|
const report = await provider.usage(secrets, { http: deps.http, now: deps.now }, credential.providerData);
|
|
35688
35993
|
if (report === null || report.windows.length === 0)
|
|
35689
35994
|
return null;
|
|
@@ -35846,6 +36151,12 @@ function quotaOps(deps) {
|
|
|
35846
36151
|
outcomes.push(result?.outcome ?? { kind: "failed", credentialId: credential.id, code: "INTERNAL" });
|
|
35847
36152
|
}
|
|
35848
36153
|
return { outcomes };
|
|
36154
|
+
},
|
|
36155
|
+
resetCredits: (credentialId) => listResetCredits(deps, credentialId),
|
|
36156
|
+
redeemReset: (request2) => redeemResetCredit(deps, request2),
|
|
36157
|
+
hasResets: (provider) => {
|
|
36158
|
+
const flow = deps.providers[provider];
|
|
36159
|
+
return flow?.resetCredits !== undefined && flow.redeemReset !== undefined;
|
|
35849
36160
|
}
|
|
35850
36161
|
};
|
|
35851
36162
|
}
|
|
@@ -38030,16 +38341,7 @@ var quotaRefresh = {
|
|
|
38030
38341
|
const store = await ctx.store();
|
|
38031
38342
|
const credentials = await listCredentials(store);
|
|
38032
38343
|
const wanted = id === undefined ? credentials : credentials.filter((c) => c.id === id);
|
|
38033
|
-
const
|
|
38034
|
-
const http = nodeHttpClient();
|
|
38035
|
-
const ops = quotaOps({
|
|
38036
|
-
store,
|
|
38037
|
-
coord: memoryCoord({ now: ctx.now }),
|
|
38038
|
-
providers,
|
|
38039
|
-
http,
|
|
38040
|
-
refresh: createRefresher({ store, providers, http, now: ctx.now }),
|
|
38041
|
-
now: ctx.now
|
|
38042
|
-
});
|
|
38344
|
+
const ops = await opsFor(ctx, wanted);
|
|
38043
38345
|
note(ctx, writer, id === undefined ? "refreshing every account\u2026" : `refreshing ${id}\u2026`);
|
|
38044
38346
|
const result = await ops.refresh(id === undefined ? { kind: "all" } : { kind: "one", credentialId: id });
|
|
38045
38347
|
const labels = new Map(credentials.map((c) => [c.id, c.label]));
|
|
@@ -38065,6 +38367,59 @@ var quotaRefresh = {
|
|
|
38065
38367
|
}
|
|
38066
38368
|
}
|
|
38067
38369
|
};
|
|
38370
|
+
async function opsFor(ctx, wanted) {
|
|
38371
|
+
const store = await ctx.store();
|
|
38372
|
+
const providers = wanted.every((c) => Object.hasOwn(PROVIDER_DESCRIPTORS, c.provider)) ? OAUTH_PROVIDERS : (await connectRegistryFor(ctx.root.root)).providers;
|
|
38373
|
+
const http = nodeHttpClient();
|
|
38374
|
+
return quotaOps({
|
|
38375
|
+
store,
|
|
38376
|
+
coord: memoryCoord({ now: ctx.now }),
|
|
38377
|
+
providers,
|
|
38378
|
+
http,
|
|
38379
|
+
refresh: createRefresher({ store, providers, http, now: ctx.now }),
|
|
38380
|
+
now: ctx.now
|
|
38381
|
+
});
|
|
38382
|
+
}
|
|
38383
|
+
var quotaResets = {
|
|
38384
|
+
usage: "quota resets <id>",
|
|
38385
|
+
summary: "List an account's banked quota resets (Codex, Claude)",
|
|
38386
|
+
async run(args, { ctx, writer }) {
|
|
38387
|
+
const id = requirePositional(args, 0, "credential id");
|
|
38388
|
+
const credentials = (await listCredentials(await ctx.store())).filter((c) => c.id === id);
|
|
38389
|
+
const listed = await (await opsFor(ctx, credentials)).resetCredits(id);
|
|
38390
|
+
emit(ctx, writer, listed, () => [
|
|
38391
|
+
table([{ header: "CREDIT" }, { header: "STATUS" }, { header: "TITLE" }, { header: "EXPIRES" }], listed.credits.map((c) => [c.id, c.status, c.title ?? dash, formatTime(c.expiresAt)])),
|
|
38392
|
+
"",
|
|
38393
|
+
`${listed.available} available`
|
|
38394
|
+
].join(`
|
|
38395
|
+
`));
|
|
38396
|
+
}
|
|
38397
|
+
};
|
|
38398
|
+
var quotaReset = {
|
|
38399
|
+
usage: "quota reset <id> [--credit CREDIT_ID]",
|
|
38400
|
+
summary: "Spend one banked quota reset on an account (irreversible)",
|
|
38401
|
+
options: { credit: { type: "string" } },
|
|
38402
|
+
async run(args, { ctx, writer, prompt }) {
|
|
38403
|
+
const id = requirePositional(args, 0, "credential id");
|
|
38404
|
+
const creditId = stringFlag(args.values, "credit");
|
|
38405
|
+
const credentials = (await listCredentials(await ctx.store())).filter((c) => c.id === id);
|
|
38406
|
+
const label3 = credentials[0]?.label ?? id;
|
|
38407
|
+
const ops = await opsFor(ctx, credentials);
|
|
38408
|
+
const provider2 = credentials[0]?.provider;
|
|
38409
|
+
if (provider2 === undefined)
|
|
38410
|
+
throw new CliError("no such credential");
|
|
38411
|
+
if (!ops.hasResets(provider2))
|
|
38412
|
+
throw new CliError("this account's provider has no quota resets");
|
|
38413
|
+
if (!await prompt.confirm(`spend one banked quota reset on "${label3}" (${id})?`)) {
|
|
38414
|
+
throw new CliError("cancelled");
|
|
38415
|
+
}
|
|
38416
|
+
const result = await ops.redeemReset({
|
|
38417
|
+
credentialId: id,
|
|
38418
|
+
...creditId === undefined ? {} : { creditId }
|
|
38419
|
+
});
|
|
38420
|
+
emit(ctx, writer, result, () => `${label3}: reset ${result.creditId} redeemed` + (result.windowsReset === null ? "" : `, ${result.windowsReset} window(s) reset`) + (result.quotaRefreshed ? "; quota re-read" : "; quota re-read failed, next poll will update it"));
|
|
38421
|
+
}
|
|
38422
|
+
};
|
|
38068
38423
|
|
|
38069
38424
|
// apps/cli/src/commands/service.ts
|
|
38070
38425
|
import { existsSync as existsSync5 } from "fs";
|
|
@@ -38155,7 +38510,7 @@ function createServiceDeps(input2) {
|
|
|
38155
38510
|
}
|
|
38156
38511
|
|
|
38157
38512
|
// apps/cli/src/version.ts
|
|
38158
|
-
var VERSION = "0.12.
|
|
38513
|
+
var VERSION = "0.12.13";
|
|
38159
38514
|
|
|
38160
38515
|
// apps/cli/src/commands/service.ts
|
|
38161
38516
|
function gatewayArgv(root) {
|
|
@@ -38872,6 +39227,8 @@ var COMMANDS = {
|
|
|
38872
39227
|
"credentials add-key": credentialsAddKey,
|
|
38873
39228
|
"credentials health": credentialsHealth,
|
|
38874
39229
|
"quota refresh": quotaRefresh,
|
|
39230
|
+
"quota resets": quotaResets,
|
|
39231
|
+
"quota reset": quotaReset,
|
|
38875
39232
|
"models list": modelsList,
|
|
38876
39233
|
"models show": modelsShow,
|
|
38877
39234
|
"models put": modelsPut,
|