@omnicross/daemon 0.3.1 → 0.4.0
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/dist/cli.cjs +1299 -275
- package/dist/cli.js +1255 -224
- package/dist/index.cjs +1194 -268
- package/dist/index.d.cts +160 -8
- package/dist/index.d.ts +160 -8
- package/dist/index.js +1191 -260
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -18,14 +18,14 @@ import { setSubscriptionRegistryForOutbound } from "@omnicross/core/outbound-api
|
|
|
18
18
|
import { getSharedAccountHealth as getSharedAccountHealth4 } from "@omnicross/core/pipeline/SubscriptionAccountHealth";
|
|
19
19
|
import {
|
|
20
20
|
__resetSharedAccountAllowanceStoreForTests,
|
|
21
|
-
AccountAllowanceStore as
|
|
21
|
+
AccountAllowanceStore as AccountAllowanceStore8,
|
|
22
22
|
setSharedAccountAllowanceStore
|
|
23
23
|
} from "@omnicross/core/pipeline/AccountAllowanceStore";
|
|
24
24
|
import {
|
|
25
25
|
__resetSharedAccountAllowanceSchedulingForTests,
|
|
26
26
|
getSharedAccountAllowanceScheduling as getSharedAccountAllowanceScheduling5
|
|
27
27
|
} from "@omnicross/core/pipeline/AccountAllowanceScheduling";
|
|
28
|
-
import { fetchUpstream as
|
|
28
|
+
import { fetchUpstream as fetchUpstream13, setUpstreamProxyResolver } from "@omnicross/core/pipeline/upstreamFetch";
|
|
29
29
|
import { __resetSharedIdentityStoreForTests } from "@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore";
|
|
30
30
|
import { setGeminiCodeAssistResolver } from "@omnicross/core/ports/gemini-code-assist-resolver";
|
|
31
31
|
import {
|
|
@@ -230,9 +230,188 @@ function handleKimiOAuthStatus(sessionId, deps) {
|
|
|
230
230
|
return { status: 200, body: { state: s.status, ...s.error ? { message: s.error } : {} } };
|
|
231
231
|
}
|
|
232
232
|
|
|
233
|
+
// src/admin/accountsGrokOAuth.ts
|
|
234
|
+
import { grokOAuth } from "@omnicross/subscriptions";
|
|
235
|
+
function err3(status, message) {
|
|
236
|
+
return { status, body: { error: { type: "admin_api_error", message } } };
|
|
237
|
+
}
|
|
238
|
+
var DEFAULT_GROK_OAUTH_TTL_MS = 15 * 6e4;
|
|
239
|
+
async function handleGrokOAuthStart(deps) {
|
|
240
|
+
if (deps.grokSessions.isBusy()) {
|
|
241
|
+
return err3(409, "a grok sign-in is already in progress \u2014 finish it in the browser or cancel it");
|
|
242
|
+
}
|
|
243
|
+
const fetchImpl = deps.oauthExchangeFetch("grok");
|
|
244
|
+
let tokenEndpoint;
|
|
245
|
+
try {
|
|
246
|
+
tokenEndpoint = await grokOAuth.resolveGrokTokenEndpoint(fetchImpl);
|
|
247
|
+
} catch (e) {
|
|
248
|
+
const reason = e instanceof Error ? e.message : "OIDC discovery failed";
|
|
249
|
+
return err3(502, `grok token-endpoint discovery failed: ${reason}`);
|
|
250
|
+
}
|
|
251
|
+
let authorization;
|
|
252
|
+
try {
|
|
253
|
+
authorization = await grokOAuth.requestGrokDeviceAuthorization(fetchImpl);
|
|
254
|
+
} catch (e) {
|
|
255
|
+
const reason = e instanceof Error ? e.message : "device authorization failed";
|
|
256
|
+
return err3(502, `grok device authorization failed: ${reason}`);
|
|
257
|
+
}
|
|
258
|
+
const { sessionId, signal } = deps.grokSessions.begin();
|
|
259
|
+
void runGrokDevicePoll(sessionId, tokenEndpoint, authorization.deviceCode, signal, deps).catch((e) => {
|
|
260
|
+
const reason = e instanceof Error ? e.message : "grok sign-in failed";
|
|
261
|
+
deps.grokSessions.settle(sessionId, "error", reason);
|
|
262
|
+
});
|
|
263
|
+
return {
|
|
264
|
+
status: 200,
|
|
265
|
+
body: {
|
|
266
|
+
authUrl: authorization.verificationUriComplete ?? authorization.verificationUri,
|
|
267
|
+
userCode: authorization.userCode,
|
|
268
|
+
sessionId
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
async function runGrokDevicePoll(sessionId, tokenEndpoint, deviceCode, signal, deps) {
|
|
273
|
+
const fetchImpl = deps.oauthExchangeFetch("grok");
|
|
274
|
+
const result = await grokOAuth.awaitGrokDeviceToken(
|
|
275
|
+
{ userCode: "", deviceCode, verificationUri: "" },
|
|
276
|
+
tokenEndpoint,
|
|
277
|
+
fetchImpl,
|
|
278
|
+
{
|
|
279
|
+
deadlineMs: DEFAULT_GROK_OAUTH_TTL_MS,
|
|
280
|
+
sleep: (ms) => new Promise((resolve10, reject) => {
|
|
281
|
+
const onAbort = () => {
|
|
282
|
+
clearTimeout(timer);
|
|
283
|
+
reject(new Error("login: cancelled"));
|
|
284
|
+
};
|
|
285
|
+
const timer = setTimeout(() => {
|
|
286
|
+
signal.removeEventListener("abort", onAbort);
|
|
287
|
+
resolve10();
|
|
288
|
+
}, ms);
|
|
289
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
290
|
+
})
|
|
291
|
+
}
|
|
292
|
+
);
|
|
293
|
+
const block = {
|
|
294
|
+
authMethod: "oauth",
|
|
295
|
+
status: "authorized",
|
|
296
|
+
accessToken: result.accessToken,
|
|
297
|
+
refreshToken: result.refreshToken,
|
|
298
|
+
expiresAt: new Date(Date.now() + result.expiresIn * 1e3).toISOString(),
|
|
299
|
+
accountId: grokOAuth.grokAccountIdFromAccessToken(result.accessToken),
|
|
300
|
+
lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
301
|
+
};
|
|
302
|
+
await deps.subscriptionAccountAppender.appendProviderAccount("grok", block);
|
|
303
|
+
deps.grokSessions.settle(sessionId, "done");
|
|
304
|
+
}
|
|
305
|
+
function handleGrokOAuthCancel(sessionId, deps) {
|
|
306
|
+
if (!deps.grokSessions.cancel(sessionId)) return err3(404, "unknown or expired grok sign-in session");
|
|
307
|
+
return { status: 200, body: { ok: true } };
|
|
308
|
+
}
|
|
309
|
+
function handleGrokOAuthStatus(sessionId, deps) {
|
|
310
|
+
const s = deps.grokSessions.get(sessionId);
|
|
311
|
+
if (!s) return err3(404, "unknown or expired grok sign-in session");
|
|
312
|
+
return { status: 200, body: { state: s.status, ...s.error ? { message: s.error } : {} } };
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// src/admin/accountsCopilotOAuth.ts
|
|
316
|
+
import { copilotOAuth } from "@omnicross/subscriptions";
|
|
317
|
+
function err4(status, message) {
|
|
318
|
+
return { status, body: { error: { type: "admin_api_error", message } } };
|
|
319
|
+
}
|
|
320
|
+
var DEFAULT_COPILOT_OAUTH_TTL_MS = 15 * 6e4;
|
|
321
|
+
async function handleCopilotOAuthStart(deps, enterpriseUrlInput) {
|
|
322
|
+
if (deps.copilotSessions.isBusy()) {
|
|
323
|
+
return err4(409, "a copilot sign-in is already in progress \u2014 finish it in the browser or cancel it");
|
|
324
|
+
}
|
|
325
|
+
let enterpriseUrl;
|
|
326
|
+
if (typeof enterpriseUrlInput === "string" && enterpriseUrlInput.trim()) {
|
|
327
|
+
try {
|
|
328
|
+
enterpriseUrl = copilotOAuth.normalizeCopilotEnterpriseDomain(enterpriseUrlInput);
|
|
329
|
+
} catch (e) {
|
|
330
|
+
const reason = e instanceof Error ? e.message : "invalid GitHub Enterprise domain";
|
|
331
|
+
return err4(400, `copilot ${reason}`);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
const fetchImpl = deps.oauthExchangeFetch("copilot");
|
|
335
|
+
let authorization;
|
|
336
|
+
try {
|
|
337
|
+
authorization = await copilotOAuth.requestCopilotDeviceAuthorization(fetchImpl, enterpriseUrl);
|
|
338
|
+
} catch (e) {
|
|
339
|
+
const reason = e instanceof Error ? e.message : "device authorization failed";
|
|
340
|
+
return err4(502, `copilot device authorization failed: ${reason}`);
|
|
341
|
+
}
|
|
342
|
+
const { sessionId, signal } = deps.copilotSessions.begin();
|
|
343
|
+
void runCopilotDevicePoll(sessionId, authorization.deviceCode, signal, deps, enterpriseUrl).catch((e) => {
|
|
344
|
+
const reason = e instanceof Error ? e.message : "copilot sign-in failed";
|
|
345
|
+
deps.copilotSessions.settle(sessionId, "error", reason);
|
|
346
|
+
});
|
|
347
|
+
return {
|
|
348
|
+
status: 200,
|
|
349
|
+
body: {
|
|
350
|
+
authUrl: authorization.verificationUri,
|
|
351
|
+
userCode: authorization.userCode,
|
|
352
|
+
sessionId,
|
|
353
|
+
...enterpriseUrl ? { enterpriseUrl } : {}
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
async function runCopilotDevicePoll(sessionId, deviceCode, signal, deps, enterpriseUrl) {
|
|
358
|
+
const fetchImpl = deps.oauthExchangeFetch("copilot");
|
|
359
|
+
const result = await copilotOAuth.awaitCopilotDeviceToken(
|
|
360
|
+
{ userCode: "", deviceCode, verificationUri: "", interval: 5, expiresIn: 900 },
|
|
361
|
+
fetchImpl,
|
|
362
|
+
{
|
|
363
|
+
deadlineMs: DEFAULT_COPILOT_OAUTH_TTL_MS,
|
|
364
|
+
...enterpriseUrl ? { enterpriseUrl } : {},
|
|
365
|
+
sleep: (ms) => new Promise((resolve10, reject) => {
|
|
366
|
+
const onAbort = () => {
|
|
367
|
+
clearTimeout(timer);
|
|
368
|
+
reject(new Error("login: cancelled"));
|
|
369
|
+
};
|
|
370
|
+
const timer = setTimeout(() => {
|
|
371
|
+
signal.removeEventListener("abort", onAbort);
|
|
372
|
+
resolve10();
|
|
373
|
+
}, ms);
|
|
374
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
375
|
+
})
|
|
376
|
+
}
|
|
377
|
+
);
|
|
378
|
+
const identity = await copilotOAuth.fetchCopilotIdentity(result.accessToken, fetchImpl, enterpriseUrl);
|
|
379
|
+
const apiEndpoint = await copilotOAuth.discoverCopilotApiEndpoint(result.accessToken, fetchImpl, enterpriseUrl);
|
|
380
|
+
await copilotOAuth.enableAllCopilotModels(
|
|
381
|
+
result.accessToken,
|
|
382
|
+
{ apiEndpoint, ...enterpriseUrl ? { enterpriseUrl } : {} },
|
|
383
|
+
fetchImpl
|
|
384
|
+
);
|
|
385
|
+
const block = {
|
|
386
|
+
authMethod: "oauth",
|
|
387
|
+
status: "authorized",
|
|
388
|
+
accessToken: result.accessToken,
|
|
389
|
+
refreshToken: result.accessToken,
|
|
390
|
+
expiresAt: new Date(Date.now() + copilotOAuth.COPILOT_FAR_FUTURE_MS).toISOString(),
|
|
391
|
+
...identity.accountId ? { accountId: identity.accountId } : {},
|
|
392
|
+
...identity.email ? { email: identity.email } : {},
|
|
393
|
+
...apiEndpoint ? { apiEndpoint } : {},
|
|
394
|
+
...enterpriseUrl ? { enterpriseUrl } : {},
|
|
395
|
+
lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
396
|
+
};
|
|
397
|
+
await deps.subscriptionAccountAppender.appendProviderAccount("copilot", block);
|
|
398
|
+
deps.copilotSessions.settle(sessionId, "done");
|
|
399
|
+
}
|
|
400
|
+
function handleCopilotOAuthCancel(sessionId, deps) {
|
|
401
|
+
if (!deps.copilotSessions.cancel(sessionId)) {
|
|
402
|
+
return err4(404, "unknown or expired copilot sign-in session");
|
|
403
|
+
}
|
|
404
|
+
return { status: 200, body: { ok: true } };
|
|
405
|
+
}
|
|
406
|
+
function handleCopilotOAuthStatus(sessionId, deps) {
|
|
407
|
+
const s = deps.copilotSessions.get(sessionId);
|
|
408
|
+
if (!s) return err4(404, "unknown or expired copilot sign-in session");
|
|
409
|
+
return { status: 200, body: { state: s.status, ...s.error ? { message: s.error } : {} } };
|
|
410
|
+
}
|
|
411
|
+
|
|
233
412
|
// src/allowance/AccountAllowanceService.ts
|
|
234
413
|
import {
|
|
235
|
-
getSharedAccountAllowanceStore as
|
|
414
|
+
getSharedAccountAllowanceStore as getSharedAccountAllowanceStore7
|
|
236
415
|
} from "@omnicross/core/pipeline/AccountAllowanceStore";
|
|
237
416
|
import {
|
|
238
417
|
getSharedAccountAllowanceScheduling
|
|
@@ -763,67 +942,548 @@ function secondsUntil3(instant, now) {
|
|
|
763
942
|
if (!instant) return void 0;
|
|
764
943
|
return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
|
|
765
944
|
}
|
|
766
|
-
function windowFromRow(row, fallback, now) {
|
|
767
|
-
const usedPercent = row?.limit !== void 0 && row.limit > 0 && row.used !== void 0 ? Math.round(Math.min(100, row.used / row.limit * 100) * 10) / 10 : null;
|
|
768
|
-
const resetsAt = row?.resetsAtMs !== void 0 ? new Date(row.resetsAtMs).toISOString() : void 0;
|
|
769
|
-
return {
|
|
770
|
-
id: fallback.id,
|
|
771
|
-
label: fallback.label,
|
|
772
|
-
scope: "all",
|
|
773
|
-
usedPercent,
|
|
774
|
-
windowMinutes: fallback.minutes,
|
|
775
|
-
...resetsAt !== void 0 ? { resetsAt } : {},
|
|
776
|
-
remainingSeconds: secondsUntil3(resetsAt, now),
|
|
777
|
-
state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
|
|
778
|
-
};
|
|
779
|
-
}
|
|
780
|
-
function parseKimiUsagePayload(payload, now) {
|
|
781
|
-
if (!isRecord(payload)) return [];
|
|
782
|
-
const byId = /* @__PURE__ */ new Map();
|
|
783
|
-
const rowFrom = (data) => {
|
|
784
|
-
const limit = finiteNumber2(data["limit"]);
|
|
785
|
-
let used = finiteNumber2(data["used"]);
|
|
786
|
-
const remaining = finiteNumber2(data["remaining"]);
|
|
787
|
-
if (used === void 0 && remaining !== void 0 && limit !== void 0) {
|
|
788
|
-
used = limit - remaining;
|
|
789
|
-
}
|
|
790
|
-
let windowDurationMs;
|
|
791
|
-
const windowData = isRecord(data["window"]) ? data["window"] : void 0;
|
|
792
|
-
const duration = finiteNumber2(windowData?.["duration"]);
|
|
793
|
-
const timeUnit = typeof windowData?.["timeUnit"] === "string" ? windowData["timeUnit"].toUpperCase() : "";
|
|
794
|
-
if (duration !== void 0) {
|
|
795
|
-
if (timeUnit.includes("MINUTE")) windowDurationMs = duration * MINUTE_MS;
|
|
796
|
-
else if (timeUnit.includes("HOUR")) windowDurationMs = duration * HOUR_MS;
|
|
797
|
-
else if (timeUnit.includes("DAY")) windowDurationMs = duration * DAY_MS;
|
|
798
|
-
else if (timeUnit.includes("WEEK")) windowDurationMs = duration * 7 * DAY_MS;
|
|
799
|
-
else if (timeUnit.includes("SECOND")) windowDurationMs = duration * 1e3;
|
|
945
|
+
function windowFromRow(row, fallback, now) {
|
|
946
|
+
const usedPercent = row?.limit !== void 0 && row.limit > 0 && row.used !== void 0 ? Math.round(Math.min(100, row.used / row.limit * 100) * 10) / 10 : null;
|
|
947
|
+
const resetsAt = row?.resetsAtMs !== void 0 ? new Date(row.resetsAtMs).toISOString() : void 0;
|
|
948
|
+
return {
|
|
949
|
+
id: fallback.id,
|
|
950
|
+
label: fallback.label,
|
|
951
|
+
scope: "all",
|
|
952
|
+
usedPercent,
|
|
953
|
+
windowMinutes: fallback.minutes,
|
|
954
|
+
...resetsAt !== void 0 ? { resetsAt } : {},
|
|
955
|
+
remainingSeconds: secondsUntil3(resetsAt, now),
|
|
956
|
+
state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
|
|
957
|
+
};
|
|
958
|
+
}
|
|
959
|
+
function parseKimiUsagePayload(payload, now) {
|
|
960
|
+
if (!isRecord(payload)) return [];
|
|
961
|
+
const byId = /* @__PURE__ */ new Map();
|
|
962
|
+
const rowFrom = (data) => {
|
|
963
|
+
const limit = finiteNumber2(data["limit"]);
|
|
964
|
+
let used = finiteNumber2(data["used"]);
|
|
965
|
+
const remaining = finiteNumber2(data["remaining"]);
|
|
966
|
+
if (used === void 0 && remaining !== void 0 && limit !== void 0) {
|
|
967
|
+
used = limit - remaining;
|
|
968
|
+
}
|
|
969
|
+
let windowDurationMs;
|
|
970
|
+
const windowData = isRecord(data["window"]) ? data["window"] : void 0;
|
|
971
|
+
const duration = finiteNumber2(windowData?.["duration"]);
|
|
972
|
+
const timeUnit = typeof windowData?.["timeUnit"] === "string" ? windowData["timeUnit"].toUpperCase() : "";
|
|
973
|
+
if (duration !== void 0) {
|
|
974
|
+
if (timeUnit.includes("MINUTE")) windowDurationMs = duration * MINUTE_MS;
|
|
975
|
+
else if (timeUnit.includes("HOUR")) windowDurationMs = duration * HOUR_MS;
|
|
976
|
+
else if (timeUnit.includes("DAY")) windowDurationMs = duration * DAY_MS;
|
|
977
|
+
else if (timeUnit.includes("WEEK")) windowDurationMs = duration * 7 * DAY_MS;
|
|
978
|
+
else if (timeUnit.includes("SECOND")) windowDurationMs = duration * 1e3;
|
|
979
|
+
}
|
|
980
|
+
const resetsAtMs = parseResetMs(windowData && parseResetMs(windowData, now) !== void 0 ? windowData : data, now);
|
|
981
|
+
return { used, limit, remaining, ...resetsAtMs !== void 0 ? { resetsAtMs } : {}, ...windowDurationMs !== void 0 ? { windowDurationMs } : {} };
|
|
982
|
+
};
|
|
983
|
+
if (isRecord(payload["usage"])) {
|
|
984
|
+
const row = rowFrom(payload["usage"]);
|
|
985
|
+
const window = windowFromRow({ ...row, resetsAtMs: row.resetsAtMs }, { id: "seven-day", label: "7 days", minutes: 10080 }, now);
|
|
986
|
+
byId.set("seven-day", window);
|
|
987
|
+
}
|
|
988
|
+
if (Array.isArray(payload["limits"])) {
|
|
989
|
+
for (const item of payload["limits"]) {
|
|
990
|
+
if (!isRecord(item)) continue;
|
|
991
|
+
const detail = isRecord(item["detail"]) ? item["detail"] : item;
|
|
992
|
+
const row = rowFrom(detail);
|
|
993
|
+
const canonical = row.windowDurationMs !== void 0 ? canonicalWindow(row.windowDurationMs) : void 0;
|
|
994
|
+
if (!canonical) continue;
|
|
995
|
+
const window = windowFromRow(row, canonical, now);
|
|
996
|
+
const existing = byId.get(canonical.id);
|
|
997
|
+
if (!existing || (window.usedPercent ?? 0) > (existing.usedPercent ?? 0)) {
|
|
998
|
+
byId.set(canonical.id, window);
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
return [...byId.values()].sort((a, b) => (a.windowMinutes ?? Infinity) - (b.windowMinutes ?? Infinity)).slice(0, 4);
|
|
1003
|
+
}
|
|
1004
|
+
var KimiAllowanceCollector = class {
|
|
1005
|
+
constructor(credentials, store = getSharedAccountAllowanceStore3(), fetchImpl = (url, init, accountId) => fetchUpstream3(url, init, { providerId: "kimi", accountId, redactBodies: true }), now = Date.now) {
|
|
1006
|
+
this.credentials = credentials;
|
|
1007
|
+
this.store = store;
|
|
1008
|
+
this.fetchImpl = fetchImpl;
|
|
1009
|
+
this.now = now;
|
|
1010
|
+
}
|
|
1011
|
+
credentials;
|
|
1012
|
+
store;
|
|
1013
|
+
fetchImpl;
|
|
1014
|
+
now;
|
|
1015
|
+
inFlight = /* @__PURE__ */ new Map();
|
|
1016
|
+
async collectMany(accounts, options = {}) {
|
|
1017
|
+
const settled = await Promise.allSettled(accounts.map((account) => this.collect(account, options)));
|
|
1018
|
+
return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
|
|
1019
|
+
}
|
|
1020
|
+
collect(account, options = {}) {
|
|
1021
|
+
const now = this.now();
|
|
1022
|
+
if (account.tokens.authMethod !== "oauth") {
|
|
1023
|
+
const existing = this.store.get("kimi", account.id, now);
|
|
1024
|
+
if (existing?.windows.every((window) => window.state === "unsupported")) {
|
|
1025
|
+
return Promise.resolve(existing);
|
|
1026
|
+
}
|
|
1027
|
+
const snapshot = this.unsupportedSnapshot(account.id, now);
|
|
1028
|
+
this.store.set(snapshot);
|
|
1029
|
+
return Promise.resolve(snapshot);
|
|
1030
|
+
}
|
|
1031
|
+
const cached = this.store.get("kimi", account.id, now);
|
|
1032
|
+
if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) {
|
|
1033
|
+
return Promise.resolve(cached);
|
|
1034
|
+
}
|
|
1035
|
+
const running = this.inFlight.get(account.id);
|
|
1036
|
+
if (running) return running;
|
|
1037
|
+
const promise = this.fetchAccount(account.id, account.tokens).catch(() => this.failureSnapshot(account.id, "kimi_usage_request_failed", this.now())).finally(() => this.inFlight.delete(account.id));
|
|
1038
|
+
this.inFlight.set(account.id, promise);
|
|
1039
|
+
return promise;
|
|
1040
|
+
}
|
|
1041
|
+
isCacheValid(snapshot, now, refreshAheadMs) {
|
|
1042
|
+
if (snapshot.windows.every((window) => window.state === "unsupported")) return true;
|
|
1043
|
+
const expiresAt = snapshot.expiresAt ? Date.parse(snapshot.expiresAt) : 0;
|
|
1044
|
+
const ahead = typeof refreshAheadMs === "number" && Number.isFinite(refreshAheadMs) ? Math.max(0, refreshAheadMs) : 0;
|
|
1045
|
+
return Number.isFinite(expiresAt) && expiresAt > now + ahead;
|
|
1046
|
+
}
|
|
1047
|
+
async fetchAccount(accountId, tokens) {
|
|
1048
|
+
let accessToken = await this.credentials.getAccessTokenForAccount("kimi", accountId);
|
|
1049
|
+
if (!accessToken) return this.failureSnapshot(accountId, "kimi_usage_token_unavailable", this.now());
|
|
1050
|
+
let response = await this.request(accountId, accessToken, tokens);
|
|
1051
|
+
if (response.status === 401) {
|
|
1052
|
+
const refreshed = await this.credentials.refreshAccountToken("kimi", accountId);
|
|
1053
|
+
if (!refreshed) return this.failureSnapshot(accountId, "kimi_usage_unauthorized", this.now());
|
|
1054
|
+
accessToken = await this.credentials.getAccessTokenForAccount("kimi", accountId);
|
|
1055
|
+
if (!accessToken) return this.failureSnapshot(accountId, "kimi_usage_token_unavailable", this.now());
|
|
1056
|
+
response = await this.request(accountId, accessToken, tokens);
|
|
1057
|
+
}
|
|
1058
|
+
if (response.status === 403) {
|
|
1059
|
+
const snapshot2 = this.unsupportedSnapshot(accountId, this.now(), "kimi_usage_unsupported");
|
|
1060
|
+
this.store.set(snapshot2);
|
|
1061
|
+
return snapshot2;
|
|
1062
|
+
}
|
|
1063
|
+
if (!response.ok) return this.failureSnapshot(accountId, "kimi_usage_http_error", this.now());
|
|
1064
|
+
let payload;
|
|
1065
|
+
try {
|
|
1066
|
+
payload = await response.json();
|
|
1067
|
+
} catch {
|
|
1068
|
+
return this.failureSnapshot(accountId, "kimi_usage_invalid_response", this.now());
|
|
1069
|
+
}
|
|
1070
|
+
const now = this.now();
|
|
1071
|
+
const windows = parseKimiUsagePayload(payload, now);
|
|
1072
|
+
const snapshot = {
|
|
1073
|
+
providerId: "kimi",
|
|
1074
|
+
accountId,
|
|
1075
|
+
source: "oauth-usage-api",
|
|
1076
|
+
observedAt: new Date(now).toISOString(),
|
|
1077
|
+
expiresAt: new Date(now + KIMI_ALLOWANCE_CACHE_MS).toISOString(),
|
|
1078
|
+
windows: windows.length > 0 ? windows : [
|
|
1079
|
+
{ id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unavailable" },
|
|
1080
|
+
{ id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" }
|
|
1081
|
+
],
|
|
1082
|
+
...windows.length > 0 ? {} : { lastErrorCode: "kimi_usage_invalid_response" }
|
|
1083
|
+
};
|
|
1084
|
+
this.store.set(snapshot);
|
|
1085
|
+
return snapshot;
|
|
1086
|
+
}
|
|
1087
|
+
request(accountId, accessToken, tokens) {
|
|
1088
|
+
return this.fetchImpl(KIMI_USAGE_URL, {
|
|
1089
|
+
method: "GET",
|
|
1090
|
+
headers: {
|
|
1091
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1092
|
+
Accept: "application/json",
|
|
1093
|
+
...kimiFingerprintHeaders(tokens.deviceId)
|
|
1094
|
+
},
|
|
1095
|
+
signal: AbortSignal.timeout(15e3)
|
|
1096
|
+
}, accountId);
|
|
1097
|
+
}
|
|
1098
|
+
failureSnapshot(accountId, code, now) {
|
|
1099
|
+
const existing = this.store.get("kimi", accountId, now);
|
|
1100
|
+
const snapshot = existing ? {
|
|
1101
|
+
...existing,
|
|
1102
|
+
expiresAt: new Date(now + KIMI_ALLOWANCE_CACHE_MS).toISOString(),
|
|
1103
|
+
windows: existing.windows.map((window) => ({
|
|
1104
|
+
...window,
|
|
1105
|
+
state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt ? "stale" : "unavailable"
|
|
1106
|
+
})),
|
|
1107
|
+
lastErrorCode: code
|
|
1108
|
+
} : {
|
|
1109
|
+
providerId: "kimi",
|
|
1110
|
+
accountId,
|
|
1111
|
+
source: "oauth-usage-api",
|
|
1112
|
+
observedAt: new Date(now).toISOString(),
|
|
1113
|
+
expiresAt: new Date(now + KIMI_ALLOWANCE_CACHE_MS).toISOString(),
|
|
1114
|
+
windows: [
|
|
1115
|
+
{ id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unavailable" },
|
|
1116
|
+
{ id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" }
|
|
1117
|
+
],
|
|
1118
|
+
lastErrorCode: code
|
|
1119
|
+
};
|
|
1120
|
+
this.store.set(snapshot);
|
|
1121
|
+
return snapshot;
|
|
1122
|
+
}
|
|
1123
|
+
unsupportedSnapshot(accountId, now, code = "kimi_usage_unsupported_auth") {
|
|
1124
|
+
return {
|
|
1125
|
+
providerId: "kimi",
|
|
1126
|
+
accountId,
|
|
1127
|
+
source: "oauth-usage-api",
|
|
1128
|
+
observedAt: new Date(now).toISOString(),
|
|
1129
|
+
windows: [
|
|
1130
|
+
{ id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unsupported" },
|
|
1131
|
+
{ id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unsupported" }
|
|
1132
|
+
],
|
|
1133
|
+
lastErrorCode: code
|
|
1134
|
+
};
|
|
1135
|
+
}
|
|
1136
|
+
};
|
|
1137
|
+
|
|
1138
|
+
// src/allowance/GrokAllowanceCollector.ts
|
|
1139
|
+
import {
|
|
1140
|
+
getSharedAccountAllowanceStore as getSharedAccountAllowanceStore4
|
|
1141
|
+
} from "@omnicross/core/pipeline/AccountAllowanceStore";
|
|
1142
|
+
import { fetchUpstream as fetchUpstream4 } from "@omnicross/core/pipeline/upstreamFetch";
|
|
1143
|
+
var GROK_ALLOWANCE_CACHE_MS = 5 * 6e4;
|
|
1144
|
+
var GROK_BILLING_BASE = "https://cli-chat-proxy.grok.com";
|
|
1145
|
+
var GROK_BILLING_CREDITS_URL = `${GROK_BILLING_BASE}/v1/billing?format=credits`;
|
|
1146
|
+
var GROK_BILLING_MONTHLY_URL = `${GROK_BILLING_BASE}/v1/billing`;
|
|
1147
|
+
function isRecord2(value) {
|
|
1148
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
1149
|
+
}
|
|
1150
|
+
function finiteNumber3(value) {
|
|
1151
|
+
if (value === null || value === void 0 || value === "") return void 0;
|
|
1152
|
+
const parsed = typeof value === "number" ? value : Number(value);
|
|
1153
|
+
return Number.isFinite(parsed) && parsed >= 0 ? parsed : void 0;
|
|
1154
|
+
}
|
|
1155
|
+
function percent(value) {
|
|
1156
|
+
const parsed = finiteNumber3(value);
|
|
1157
|
+
return parsed !== void 0 && parsed <= 100 ? parsed : void 0;
|
|
1158
|
+
}
|
|
1159
|
+
function onDemandAmount(value) {
|
|
1160
|
+
return isRecord2(value) ? finiteNumber3(value["val"]) : void 0;
|
|
1161
|
+
}
|
|
1162
|
+
function confirmsNoMonthlyQuota(raw) {
|
|
1163
|
+
const limit = onDemandAmount(raw["monthlyLimit"]);
|
|
1164
|
+
if (limit !== void 0) return limit === 0;
|
|
1165
|
+
return parseWeeklyConfig(raw)?.inferredPercent === true;
|
|
1166
|
+
}
|
|
1167
|
+
function parseWeeklyConfig(raw) {
|
|
1168
|
+
const period = isRecord2(raw["currentPeriod"]) ? raw["currentPeriod"] : void 0;
|
|
1169
|
+
if (!period) return null;
|
|
1170
|
+
const start = typeof period["start"] === "string" ? Date.parse(period["start"]) : Number.NaN;
|
|
1171
|
+
const end = typeof period["end"] === "string" ? Date.parse(period["end"]) : Number.NaN;
|
|
1172
|
+
const type = typeof period["type"] === "string" ? period["type"] : "";
|
|
1173
|
+
if (!Number.isFinite(start) || !Number.isFinite(end) || end <= start) return null;
|
|
1174
|
+
if (!type.toUpperCase().includes("WEEK")) return null;
|
|
1175
|
+
const inferred = raw["creditUsagePercent"] === void 0 || raw["creditUsagePercent"] === null;
|
|
1176
|
+
let creditUsagePercent;
|
|
1177
|
+
if (inferred) {
|
|
1178
|
+
creditUsagePercent = end > Date.now() ? 0 : void 0;
|
|
1179
|
+
} else {
|
|
1180
|
+
creditUsagePercent = percent(raw["creditUsagePercent"]);
|
|
1181
|
+
}
|
|
1182
|
+
if (creditUsagePercent === void 0) return null;
|
|
1183
|
+
return {
|
|
1184
|
+
creditUsagePercent,
|
|
1185
|
+
inferredPercent: inferred,
|
|
1186
|
+
resetsAtMs: end,
|
|
1187
|
+
unified: raw["isUnifiedBillingUser"] === true
|
|
1188
|
+
};
|
|
1189
|
+
}
|
|
1190
|
+
function parseMonthlyConfig(raw) {
|
|
1191
|
+
const start = typeof raw["billingPeriodStart"] === "string" ? Date.parse(raw["billingPeriodStart"]) : Number.NaN;
|
|
1192
|
+
const end = typeof raw["billingPeriodEnd"] === "string" ? Date.parse(raw["billingPeriodEnd"]) : Number.NaN;
|
|
1193
|
+
if (!Number.isFinite(start) || !Number.isFinite(end) || end <= start) return null;
|
|
1194
|
+
const limit = onDemandAmount(raw["monthlyLimit"]);
|
|
1195
|
+
const used = onDemandAmount(raw["used"]);
|
|
1196
|
+
if (limit === void 0 || limit <= 0 || used === void 0) return null;
|
|
1197
|
+
return { used, limit, periodStartMs: start, periodEndMs: end };
|
|
1198
|
+
}
|
|
1199
|
+
function secondsUntil4(instant, now) {
|
|
1200
|
+
if (!instant) return void 0;
|
|
1201
|
+
return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
|
|
1202
|
+
}
|
|
1203
|
+
var MINUTE_MS2 = 6e4;
|
|
1204
|
+
var DAY_MS2 = 864e5;
|
|
1205
|
+
var WEEK_MINUTES = 7 * 24 * 60;
|
|
1206
|
+
function weeklyWindow(config, now) {
|
|
1207
|
+
const resetsAt = new Date(config.resetsAtMs).toISOString();
|
|
1208
|
+
return {
|
|
1209
|
+
id: "seven-day",
|
|
1210
|
+
label: "7 days",
|
|
1211
|
+
scope: "all",
|
|
1212
|
+
usedPercent: config.creditUsagePercent,
|
|
1213
|
+
windowMinutes: WEEK_MINUTES,
|
|
1214
|
+
resetsAt,
|
|
1215
|
+
remainingSeconds: secondsUntil4(resetsAt, now),
|
|
1216
|
+
state: "fresh"
|
|
1217
|
+
};
|
|
1218
|
+
}
|
|
1219
|
+
function monthlyWindow(config, now) {
|
|
1220
|
+
const resetsAt = new Date(config.periodEndMs).toISOString();
|
|
1221
|
+
const days = Math.max(1, Math.round((config.periodEndMs - config.periodStartMs) / DAY_MS2));
|
|
1222
|
+
return {
|
|
1223
|
+
id: "thirty-day",
|
|
1224
|
+
label: days === 30 || days === 31 ? "30 days" : `${days} days`,
|
|
1225
|
+
scope: "all",
|
|
1226
|
+
usedPercent: Math.round(Math.min(100, config.used / config.limit * 100) * 10) / 10,
|
|
1227
|
+
windowMinutes: Math.round((config.periodEndMs - config.periodStartMs) / MINUTE_MS2),
|
|
1228
|
+
resetsAt,
|
|
1229
|
+
remainingSeconds: secondsUntil4(resetsAt, now),
|
|
1230
|
+
state: "fresh"
|
|
1231
|
+
};
|
|
1232
|
+
}
|
|
1233
|
+
function onDemandWindow(raw) {
|
|
1234
|
+
const cap = onDemandAmount(raw["onDemandCap"]);
|
|
1235
|
+
const used = onDemandAmount(raw["onDemandUsed"]);
|
|
1236
|
+
if (cap === void 0 || cap <= 0 || used === void 0) return null;
|
|
1237
|
+
return {
|
|
1238
|
+
id: "on-demand",
|
|
1239
|
+
label: "On-demand",
|
|
1240
|
+
scope: "all",
|
|
1241
|
+
usedPercent: Math.round(Math.min(100, used / cap * 100) * 10) / 10,
|
|
1242
|
+
state: "fresh"
|
|
1243
|
+
};
|
|
1244
|
+
}
|
|
1245
|
+
async function probeBilling(url, accessToken, accountId, fetchImpl) {
|
|
1246
|
+
try {
|
|
1247
|
+
const response = await fetchImpl(url, {
|
|
1248
|
+
method: "GET",
|
|
1249
|
+
headers: {
|
|
1250
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1251
|
+
Accept: "application/json",
|
|
1252
|
+
"X-XAI-Token-Auth": "xai-grok-cli"
|
|
1253
|
+
},
|
|
1254
|
+
redirect: "error",
|
|
1255
|
+
signal: AbortSignal.timeout(15e3)
|
|
1256
|
+
}, accountId);
|
|
1257
|
+
if (!response.ok) return { status: response.status, payload: null };
|
|
1258
|
+
const payload = await response.json();
|
|
1259
|
+
return { status: response.status, payload: isRecord2(payload) ? payload : null };
|
|
1260
|
+
} catch {
|
|
1261
|
+
return { status: 0, payload: null };
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
function parseGrokBillingPayloads(creditsPayload, monthlyPayload, now) {
|
|
1265
|
+
const creditsConfig = isRecord2(creditsPayload?.["config"]) ? creditsPayload["config"] : null;
|
|
1266
|
+
const monthlyConfig = isRecord2(monthlyPayload?.["config"]) ? monthlyPayload["config"] : null;
|
|
1267
|
+
let weekly = creditsConfig ? parseWeeklyConfig(creditsConfig) : null;
|
|
1268
|
+
const unifiedFlag = creditsConfig?.["isUnifiedBillingUser"] === true;
|
|
1269
|
+
let monthly = monthlyConfig ? parseMonthlyConfig(monthlyConfig) : null;
|
|
1270
|
+
if (weekly?.inferredPercent && unifiedFlag) {
|
|
1271
|
+
if (monthly) {
|
|
1272
|
+
weekly = null;
|
|
1273
|
+
} else if (!monthlyConfig || !confirmsNoMonthlyQuota(monthlyConfig)) {
|
|
1274
|
+
weekly = null;
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
const windows = [];
|
|
1278
|
+
if (weekly) windows.push(weeklyWindow(weekly, now));
|
|
1279
|
+
if (monthly) windows.push(monthlyWindow(monthly, now));
|
|
1280
|
+
const onDemandSource = monthly && monthlyConfig ? monthlyConfig : creditsConfig;
|
|
1281
|
+
const onDemand = onDemandSource ? onDemandWindow(onDemandSource) : null;
|
|
1282
|
+
if (onDemand) windows.push(onDemand);
|
|
1283
|
+
return windows.length > 0 ? windows : null;
|
|
1284
|
+
}
|
|
1285
|
+
var GrokAllowanceCollector = class {
|
|
1286
|
+
constructor(credentials, store = getSharedAccountAllowanceStore4(), fetchImpl = (url, init, accountId) => fetchUpstream4(url, init, { providerId: "grok", accountId, redactBodies: true }), now = Date.now) {
|
|
1287
|
+
this.credentials = credentials;
|
|
1288
|
+
this.store = store;
|
|
1289
|
+
this.fetchImpl = fetchImpl;
|
|
1290
|
+
this.now = now;
|
|
1291
|
+
}
|
|
1292
|
+
credentials;
|
|
1293
|
+
store;
|
|
1294
|
+
fetchImpl;
|
|
1295
|
+
now;
|
|
1296
|
+
inFlight = /* @__PURE__ */ new Map();
|
|
1297
|
+
async collectMany(accounts, options = {}) {
|
|
1298
|
+
const settled = await Promise.allSettled(accounts.map((account) => this.collect(account, options)));
|
|
1299
|
+
return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
|
|
1300
|
+
}
|
|
1301
|
+
collect(account, options = {}) {
|
|
1302
|
+
const now = this.now();
|
|
1303
|
+
if (account.tokens.authMethod !== "oauth") {
|
|
1304
|
+
const existing = this.store.get("grok", account.id, now);
|
|
1305
|
+
if (existing?.windows.every((window) => window.state === "unsupported")) {
|
|
1306
|
+
return Promise.resolve(existing);
|
|
1307
|
+
}
|
|
1308
|
+
const snapshot = this.unsupportedSnapshot(account.id, now);
|
|
1309
|
+
this.store.set(snapshot);
|
|
1310
|
+
return Promise.resolve(snapshot);
|
|
1311
|
+
}
|
|
1312
|
+
const cached = this.store.get("grok", account.id, now);
|
|
1313
|
+
if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) {
|
|
1314
|
+
return Promise.resolve(cached);
|
|
1315
|
+
}
|
|
1316
|
+
const running = this.inFlight.get(account.id);
|
|
1317
|
+
if (running) return running;
|
|
1318
|
+
const promise = this.fetchAccount(account.id).catch(() => this.failureSnapshot(account.id, "grok_usage_request_failed", this.now())).finally(() => this.inFlight.delete(account.id));
|
|
1319
|
+
this.inFlight.set(account.id, promise);
|
|
1320
|
+
return promise;
|
|
1321
|
+
}
|
|
1322
|
+
isCacheValid(snapshot, now, refreshAheadMs) {
|
|
1323
|
+
if (snapshot.windows.every((window) => window.state === "unsupported")) return true;
|
|
1324
|
+
const expiresAt = snapshot.expiresAt ? Date.parse(snapshot.expiresAt) : 0;
|
|
1325
|
+
const ahead = typeof refreshAheadMs === "number" && Number.isFinite(refreshAheadMs) ? Math.max(0, refreshAheadMs) : 0;
|
|
1326
|
+
return Number.isFinite(expiresAt) && expiresAt > now + ahead;
|
|
1327
|
+
}
|
|
1328
|
+
async fetchAccount(accountId) {
|
|
1329
|
+
const probe = async () => {
|
|
1330
|
+
const accessToken = await this.credentials.getAccessTokenForAccount("grok", accountId);
|
|
1331
|
+
if (!accessToken) return { unauthorized: true, windows: null };
|
|
1332
|
+
const credits = await probeBilling(GROK_BILLING_CREDITS_URL, accessToken, accountId, this.fetchImpl);
|
|
1333
|
+
if (credits.status === 401 || credits.status === 403) return { unauthorized: true, windows: null };
|
|
1334
|
+
const creditsConfig = isRecord2(credits.payload?.["config"]) ? credits.payload["config"] : null;
|
|
1335
|
+
const weekly = creditsConfig ? parseWeeklyConfig(creditsConfig) : null;
|
|
1336
|
+
const monthly = !weekly || creditsConfig?.["isUnifiedBillingUser"] === true ? await probeBilling(GROK_BILLING_MONTHLY_URL, accessToken, accountId, this.fetchImpl) : { status: 200, payload: null };
|
|
1337
|
+
if (monthly.status === 401 || monthly.status === 403) return { unauthorized: true, windows: null };
|
|
1338
|
+
return {
|
|
1339
|
+
unauthorized: false,
|
|
1340
|
+
windows: parseGrokBillingPayloads(credits.payload, monthly.payload, this.now())
|
|
1341
|
+
};
|
|
1342
|
+
};
|
|
1343
|
+
let result = await probe();
|
|
1344
|
+
if (result.unauthorized) {
|
|
1345
|
+
const refreshed = await this.credentials.refreshAccountToken("grok", accountId);
|
|
1346
|
+
if (!refreshed) return this.failureSnapshot(accountId, "grok_usage_unauthorized", this.now());
|
|
1347
|
+
result = await probe();
|
|
1348
|
+
if (result.unauthorized) {
|
|
1349
|
+
return this.failureSnapshot(accountId, "grok_usage_unauthorized", this.now());
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
const now = this.now();
|
|
1353
|
+
if (result.windows && result.windows.length > 0) {
|
|
1354
|
+
const snapshot = {
|
|
1355
|
+
providerId: "grok",
|
|
1356
|
+
accountId,
|
|
1357
|
+
source: "oauth-usage-api",
|
|
1358
|
+
observedAt: new Date(now).toISOString(),
|
|
1359
|
+
expiresAt: new Date(now + GROK_ALLOWANCE_CACHE_MS).toISOString(),
|
|
1360
|
+
windows: result.windows
|
|
1361
|
+
};
|
|
1362
|
+
this.store.set(snapshot);
|
|
1363
|
+
return snapshot;
|
|
1364
|
+
}
|
|
1365
|
+
return this.failureSnapshot(accountId, "grok_usage_invalid_response", now);
|
|
1366
|
+
}
|
|
1367
|
+
failureSnapshot(accountId, code, now) {
|
|
1368
|
+
const existing = this.store.get("grok", accountId, now);
|
|
1369
|
+
const snapshot = existing ? {
|
|
1370
|
+
...existing,
|
|
1371
|
+
expiresAt: new Date(now + GROK_ALLOWANCE_CACHE_MS).toISOString(),
|
|
1372
|
+
windows: existing.windows.map((window) => ({
|
|
1373
|
+
...window,
|
|
1374
|
+
state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt ? "stale" : "unavailable"
|
|
1375
|
+
})),
|
|
1376
|
+
lastErrorCode: code
|
|
1377
|
+
} : {
|
|
1378
|
+
providerId: "grok",
|
|
1379
|
+
accountId,
|
|
1380
|
+
source: "oauth-usage-api",
|
|
1381
|
+
observedAt: new Date(now).toISOString(),
|
|
1382
|
+
expiresAt: new Date(now + GROK_ALLOWANCE_CACHE_MS).toISOString(),
|
|
1383
|
+
windows: [
|
|
1384
|
+
{ id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" },
|
|
1385
|
+
{ id: "thirty-day", label: "30 days", scope: "all", usedPercent: null, state: "unavailable" }
|
|
1386
|
+
],
|
|
1387
|
+
lastErrorCode: code
|
|
1388
|
+
};
|
|
1389
|
+
this.store.set(snapshot);
|
|
1390
|
+
return snapshot;
|
|
1391
|
+
}
|
|
1392
|
+
unsupportedSnapshot(accountId, now) {
|
|
1393
|
+
return {
|
|
1394
|
+
providerId: "grok",
|
|
1395
|
+
accountId,
|
|
1396
|
+
source: "oauth-usage-api",
|
|
1397
|
+
observedAt: new Date(now).toISOString(),
|
|
1398
|
+
windows: [
|
|
1399
|
+
{ id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unsupported" },
|
|
1400
|
+
{ id: "thirty-day", label: "30 days", scope: "all", usedPercent: null, state: "unsupported" }
|
|
1401
|
+
],
|
|
1402
|
+
lastErrorCode: "grok_usage_unsupported_auth"
|
|
1403
|
+
};
|
|
1404
|
+
}
|
|
1405
|
+
};
|
|
1406
|
+
|
|
1407
|
+
// src/allowance/CopilotAllowanceCollector.ts
|
|
1408
|
+
import {
|
|
1409
|
+
getSharedAccountAllowanceStore as getSharedAccountAllowanceStore5
|
|
1410
|
+
} from "@omnicross/core/pipeline/AccountAllowanceStore";
|
|
1411
|
+
import { fetchUpstream as fetchUpstream5 } from "@omnicross/core/pipeline/upstreamFetch";
|
|
1412
|
+
import { COPILOT_GITHUB_HEADERS, copilotGitHubApiBase } from "@omnicross/subscriptions";
|
|
1413
|
+
var COPILOT_ALLOWANCE_CACHE_MS = 5 * 6e4;
|
|
1414
|
+
function isRecord3(value) {
|
|
1415
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
1416
|
+
}
|
|
1417
|
+
function finiteNumber4(value) {
|
|
1418
|
+
if (value === null || value === void 0 || value === "") return void 0;
|
|
1419
|
+
const parsed = typeof value === "number" ? value : Number(value);
|
|
1420
|
+
return Number.isFinite(parsed) && parsed >= 0 ? parsed : void 0;
|
|
1421
|
+
}
|
|
1422
|
+
function booleanValue(value) {
|
|
1423
|
+
if (typeof value === "boolean") return value;
|
|
1424
|
+
if (value === "true") return true;
|
|
1425
|
+
if (value === "false") return false;
|
|
1426
|
+
return void 0;
|
|
1427
|
+
}
|
|
1428
|
+
function parseQuotaDetail(value) {
|
|
1429
|
+
if (!isRecord3(value)) return null;
|
|
1430
|
+
const entitlement = finiteNumber4(value["entitlement"]);
|
|
1431
|
+
const remaining = finiteNumber4(value["remaining"]);
|
|
1432
|
+
const percentRemaining = finiteNumber4(value["percent_remaining"]);
|
|
1433
|
+
const unlimited = booleanValue(value["unlimited"]);
|
|
1434
|
+
if (entitlement === void 0 || remaining === void 0 || percentRemaining === void 0 || unlimited === void 0) {
|
|
1435
|
+
return null;
|
|
1436
|
+
}
|
|
1437
|
+
return { entitlement, remaining, percentRemaining, unlimited };
|
|
1438
|
+
}
|
|
1439
|
+
function secondsUntil5(instant, now) {
|
|
1440
|
+
if (!instant) return void 0;
|
|
1441
|
+
return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
|
|
1442
|
+
}
|
|
1443
|
+
function parseCopilotUserPayload(payload, now) {
|
|
1444
|
+
if (!isRecord3(payload)) return null;
|
|
1445
|
+
const snapshots = isRecord3(payload["quota_snapshots"]) ? payload["quota_snapshots"] : void 0;
|
|
1446
|
+
if (!snapshots) return null;
|
|
1447
|
+
const resetRaw = payload["quota_reset_date"];
|
|
1448
|
+
const resetsAt = typeof resetRaw === "string" && resetRaw.trim() && Number.isFinite(Date.parse(resetRaw)) ? new Date(Date.parse(resetRaw)).toISOString() : void 0;
|
|
1449
|
+
const windows = [];
|
|
1450
|
+
const premium = parseQuotaDetail(snapshots["premium_interactions"]);
|
|
1451
|
+
if (premium) {
|
|
1452
|
+
const usedPercent = premium.unlimited ? 0 : premium.entitlement > 0 ? Math.round(Math.min(100, (premium.entitlement - premium.remaining) / premium.entitlement * 100) * 10) / 10 : finiteNumber4(premium.percentRemaining) !== void 0 ? Math.round(Math.min(100, Math.max(0, 100 - premium.percentRemaining)) * 10) / 10 : null;
|
|
1453
|
+
if (usedPercent !== null) {
|
|
1454
|
+
windows.push({
|
|
1455
|
+
id: "thirty-day",
|
|
1456
|
+
label: "Monthly",
|
|
1457
|
+
scope: "all",
|
|
1458
|
+
usedPercent,
|
|
1459
|
+
windowMinutes: 30 * 24 * 60,
|
|
1460
|
+
...resetsAt !== void 0 ? { resetsAt } : {},
|
|
1461
|
+
remainingSeconds: secondsUntil5(resetsAt, now),
|
|
1462
|
+
state: "fresh"
|
|
1463
|
+
});
|
|
800
1464
|
}
|
|
801
|
-
const resetsAtMs = parseResetMs(windowData && parseResetMs(windowData, now) !== void 0 ? windowData : data, now);
|
|
802
|
-
return { used, limit, remaining, ...resetsAtMs !== void 0 ? { resetsAtMs } : {}, ...windowDurationMs !== void 0 ? { windowDurationMs } : {} };
|
|
803
|
-
};
|
|
804
|
-
if (isRecord(payload["usage"])) {
|
|
805
|
-
const row = rowFrom(payload["usage"]);
|
|
806
|
-
const window = windowFromRow({ ...row, resetsAtMs: row.resetsAtMs }, { id: "seven-day", label: "7 days", minutes: 10080 }, now);
|
|
807
|
-
byId.set("seven-day", window);
|
|
808
1465
|
}
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
}
|
|
1466
|
+
const chat = parseQuotaDetail(snapshots["chat"]);
|
|
1467
|
+
if (chat && !chat.unlimited && chat.entitlement > 0) {
|
|
1468
|
+
const usedPercent = Math.round(Math.min(100, (chat.entitlement - chat.remaining) / chat.entitlement * 100) * 10) / 10;
|
|
1469
|
+
windows.push({
|
|
1470
|
+
id: "chat-monthly",
|
|
1471
|
+
label: "Chat (monthly)",
|
|
1472
|
+
scope: "all",
|
|
1473
|
+
usedPercent,
|
|
1474
|
+
windowMinutes: 30 * 24 * 60,
|
|
1475
|
+
...resetsAt !== void 0 ? { resetsAt } : {},
|
|
1476
|
+
remainingSeconds: secondsUntil5(resetsAt, now),
|
|
1477
|
+
state: "fresh"
|
|
1478
|
+
});
|
|
822
1479
|
}
|
|
823
|
-
return
|
|
1480
|
+
return windows.length > 0 ? windows : null;
|
|
824
1481
|
}
|
|
825
|
-
|
|
826
|
-
|
|
1482
|
+
function githubApiBase(tokens) {
|
|
1483
|
+
return copilotGitHubApiBase(tokens.enterpriseUrl);
|
|
1484
|
+
}
|
|
1485
|
+
var CopilotAllowanceCollector = class {
|
|
1486
|
+
constructor(credentials, store = getSharedAccountAllowanceStore5(), fetchImpl = (url, init, accountId) => fetchUpstream5(url, init, { providerId: "copilot", accountId, redactBodies: true }), now = Date.now) {
|
|
827
1487
|
this.credentials = credentials;
|
|
828
1488
|
this.store = store;
|
|
829
1489
|
this.fetchImpl = fetchImpl;
|
|
@@ -835,13 +1495,15 @@ var KimiAllowanceCollector = class {
|
|
|
835
1495
|
now;
|
|
836
1496
|
inFlight = /* @__PURE__ */ new Map();
|
|
837
1497
|
async collectMany(accounts, options = {}) {
|
|
838
|
-
const settled = await Promise.allSettled(
|
|
1498
|
+
const settled = await Promise.allSettled(
|
|
1499
|
+
accounts.map((account) => this.collect(account, options))
|
|
1500
|
+
);
|
|
839
1501
|
return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
|
|
840
1502
|
}
|
|
841
1503
|
collect(account, options = {}) {
|
|
842
1504
|
const now = this.now();
|
|
843
1505
|
if (account.tokens.authMethod !== "oauth") {
|
|
844
|
-
const existing = this.store.get("
|
|
1506
|
+
const existing = this.store.get("copilot", account.id, now);
|
|
845
1507
|
if (existing?.windows.every((window) => window.state === "unsupported")) {
|
|
846
1508
|
return Promise.resolve(existing);
|
|
847
1509
|
}
|
|
@@ -849,13 +1511,13 @@ var KimiAllowanceCollector = class {
|
|
|
849
1511
|
this.store.set(snapshot);
|
|
850
1512
|
return Promise.resolve(snapshot);
|
|
851
1513
|
}
|
|
852
|
-
const cached = this.store.get("
|
|
1514
|
+
const cached = this.store.get("copilot", account.id, now);
|
|
853
1515
|
if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) {
|
|
854
1516
|
return Promise.resolve(cached);
|
|
855
1517
|
}
|
|
856
1518
|
const running = this.inFlight.get(account.id);
|
|
857
1519
|
if (running) return running;
|
|
858
|
-
const promise = this.fetchAccount(account.id, account.tokens).catch(() => this.failureSnapshot(account.id, "
|
|
1520
|
+
const promise = this.fetchAccount(account.id, account.tokens).catch(() => this.failureSnapshot(account.id, "copilot_usage_request_failed", this.now())).finally(() => this.inFlight.delete(account.id));
|
|
859
1521
|
this.inFlight.set(account.id, promise);
|
|
860
1522
|
return promise;
|
|
861
1523
|
}
|
|
@@ -866,101 +1528,97 @@ var KimiAllowanceCollector = class {
|
|
|
866
1528
|
return Number.isFinite(expiresAt) && expiresAt > now + ahead;
|
|
867
1529
|
}
|
|
868
1530
|
async fetchAccount(accountId, tokens) {
|
|
869
|
-
let accessToken = await this.credentials.getAccessTokenForAccount("
|
|
870
|
-
if (!accessToken) return this.failureSnapshot(accountId, "
|
|
1531
|
+
let accessToken = await this.credentials.getAccessTokenForAccount("copilot", accountId);
|
|
1532
|
+
if (!accessToken) return this.failureSnapshot(accountId, "copilot_usage_token_unavailable", this.now());
|
|
871
1533
|
let response = await this.request(accountId, accessToken, tokens);
|
|
872
|
-
if (response.status === 401) {
|
|
873
|
-
const refreshed = await this.credentials.refreshAccountToken("
|
|
874
|
-
if (!refreshed) return this.failureSnapshot(accountId, "
|
|
875
|
-
accessToken = await this.credentials.getAccessTokenForAccount("
|
|
876
|
-
if (!accessToken) return this.failureSnapshot(accountId, "
|
|
1534
|
+
if (response.status === 401 || response.status === 403) {
|
|
1535
|
+
const refreshed = await this.credentials.refreshAccountToken("copilot", accountId);
|
|
1536
|
+
if (!refreshed) return this.failureSnapshot(accountId, "copilot_usage_unauthorized", this.now());
|
|
1537
|
+
accessToken = await this.credentials.getAccessTokenForAccount("copilot", accountId);
|
|
1538
|
+
if (!accessToken) return this.failureSnapshot(accountId, "copilot_usage_token_unavailable", this.now());
|
|
877
1539
|
response = await this.request(accountId, accessToken, tokens);
|
|
1540
|
+
if (response.status === 401 || response.status === 403) {
|
|
1541
|
+
return this.failureSnapshot(accountId, "copilot_usage_unauthorized", this.now());
|
|
1542
|
+
}
|
|
878
1543
|
}
|
|
879
|
-
if (response.
|
|
880
|
-
const snapshot2 = this.unsupportedSnapshot(accountId, this.now(), "kimi_usage_unsupported");
|
|
881
|
-
this.store.set(snapshot2);
|
|
882
|
-
return snapshot2;
|
|
883
|
-
}
|
|
884
|
-
if (!response.ok) return this.failureSnapshot(accountId, "kimi_usage_http_error", this.now());
|
|
1544
|
+
if (!response.ok) return this.failureSnapshot(accountId, "copilot_usage_http_error", this.now());
|
|
885
1545
|
let payload;
|
|
886
1546
|
try {
|
|
887
1547
|
payload = await response.json();
|
|
888
1548
|
} catch {
|
|
889
|
-
return this.failureSnapshot(accountId, "
|
|
1549
|
+
return this.failureSnapshot(accountId, "copilot_usage_invalid_response", this.now());
|
|
890
1550
|
}
|
|
891
1551
|
const now = this.now();
|
|
892
|
-
const windows =
|
|
1552
|
+
const windows = parseCopilotUserPayload(payload, now);
|
|
893
1553
|
const snapshot = {
|
|
894
|
-
providerId: "
|
|
1554
|
+
providerId: "copilot",
|
|
895
1555
|
accountId,
|
|
896
1556
|
source: "oauth-usage-api",
|
|
897
1557
|
observedAt: new Date(now).toISOString(),
|
|
898
|
-
expiresAt: new Date(now +
|
|
899
|
-
windows: windows
|
|
900
|
-
{ id: "
|
|
901
|
-
{ id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" }
|
|
1558
|
+
expiresAt: new Date(now + COPILOT_ALLOWANCE_CACHE_MS).toISOString(),
|
|
1559
|
+
windows: windows ?? [
|
|
1560
|
+
{ id: "thirty-day", label: "Monthly", scope: "all", usedPercent: null, state: "unavailable" }
|
|
902
1561
|
],
|
|
903
|
-
...windows
|
|
1562
|
+
...windows ? {} : { lastErrorCode: "copilot_usage_invalid_response" }
|
|
904
1563
|
};
|
|
905
1564
|
this.store.set(snapshot);
|
|
906
1565
|
return snapshot;
|
|
907
1566
|
}
|
|
908
1567
|
request(accountId, accessToken, tokens) {
|
|
909
|
-
return this.fetchImpl(
|
|
1568
|
+
return this.fetchImpl(`${githubApiBase(tokens)}/copilot_internal/user`, {
|
|
910
1569
|
method: "GET",
|
|
911
1570
|
headers: {
|
|
912
1571
|
Authorization: `Bearer ${accessToken}`,
|
|
913
1572
|
Accept: "application/json",
|
|
914
|
-
|
|
1573
|
+
"Content-Type": "application/json",
|
|
1574
|
+
...COPILOT_GITHUB_HEADERS
|
|
915
1575
|
},
|
|
916
1576
|
signal: AbortSignal.timeout(15e3)
|
|
917
1577
|
}, accountId);
|
|
918
1578
|
}
|
|
919
1579
|
failureSnapshot(accountId, code, now) {
|
|
920
|
-
const existing = this.store.get("
|
|
1580
|
+
const existing = this.store.get("copilot", accountId, now);
|
|
921
1581
|
const snapshot = existing ? {
|
|
922
1582
|
...existing,
|
|
923
|
-
expiresAt: new Date(now +
|
|
1583
|
+
expiresAt: new Date(now + COPILOT_ALLOWANCE_CACHE_MS).toISOString(),
|
|
924
1584
|
windows: existing.windows.map((window) => ({
|
|
925
1585
|
...window,
|
|
926
1586
|
state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt ? "stale" : "unavailable"
|
|
927
1587
|
})),
|
|
928
1588
|
lastErrorCode: code
|
|
929
1589
|
} : {
|
|
930
|
-
providerId: "
|
|
1590
|
+
providerId: "copilot",
|
|
931
1591
|
accountId,
|
|
932
1592
|
source: "oauth-usage-api",
|
|
933
1593
|
observedAt: new Date(now).toISOString(),
|
|
934
|
-
expiresAt: new Date(now +
|
|
1594
|
+
expiresAt: new Date(now + COPILOT_ALLOWANCE_CACHE_MS).toISOString(),
|
|
935
1595
|
windows: [
|
|
936
|
-
{ id: "
|
|
937
|
-
{ id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" }
|
|
1596
|
+
{ id: "thirty-day", label: "Monthly", scope: "all", usedPercent: null, state: "unavailable" }
|
|
938
1597
|
],
|
|
939
1598
|
lastErrorCode: code
|
|
940
1599
|
};
|
|
941
1600
|
this.store.set(snapshot);
|
|
942
1601
|
return snapshot;
|
|
943
1602
|
}
|
|
944
|
-
unsupportedSnapshot(accountId, now
|
|
1603
|
+
unsupportedSnapshot(accountId, now) {
|
|
945
1604
|
return {
|
|
946
|
-
providerId: "
|
|
1605
|
+
providerId: "copilot",
|
|
947
1606
|
accountId,
|
|
948
1607
|
source: "oauth-usage-api",
|
|
949
1608
|
observedAt: new Date(now).toISOString(),
|
|
950
1609
|
windows: [
|
|
951
|
-
{ id: "
|
|
952
|
-
{ id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unsupported" }
|
|
1610
|
+
{ id: "thirty-day", label: "Monthly", scope: "all", usedPercent: null, state: "unsupported" }
|
|
953
1611
|
],
|
|
954
|
-
lastErrorCode:
|
|
1612
|
+
lastErrorCode: "copilot_usage_unsupported_auth"
|
|
955
1613
|
};
|
|
956
1614
|
}
|
|
957
1615
|
};
|
|
958
1616
|
|
|
959
1617
|
// src/allowance/OpenCodeGoAllowanceCollector.ts
|
|
960
1618
|
import {
|
|
961
|
-
getSharedAccountAllowanceStore as
|
|
1619
|
+
getSharedAccountAllowanceStore as getSharedAccountAllowanceStore6
|
|
962
1620
|
} from "@omnicross/core/pipeline/AccountAllowanceStore";
|
|
963
|
-
import { fetchUpstream as
|
|
1621
|
+
import { fetchUpstream as fetchUpstream6 } from "@omnicross/core/pipeline/upstreamFetch";
|
|
964
1622
|
import { normalizeOpenCodeGoBaseUrl } from "@omnicross/subscriptions";
|
|
965
1623
|
var OPENCODEGO_ALLOWANCE_CACHE_MS = 5 * 6e4;
|
|
966
1624
|
var OPENCODEGO_DEFAULT_GO_BASE = "https://opencode.ai/zen/go";
|
|
@@ -974,7 +1632,7 @@ function isoInstant2(value) {
|
|
|
974
1632
|
const time = Date.parse(value);
|
|
975
1633
|
return Number.isFinite(time) ? new Date(time).toISOString() : void 0;
|
|
976
1634
|
}
|
|
977
|
-
function
|
|
1635
|
+
function secondsUntil6(instant, now) {
|
|
978
1636
|
if (!instant) return void 0;
|
|
979
1637
|
return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
|
|
980
1638
|
}
|
|
@@ -989,12 +1647,12 @@ function windowFromPayload3(id, label, minutes, payload, now) {
|
|
|
989
1647
|
usedPercent,
|
|
990
1648
|
windowMinutes: minutes,
|
|
991
1649
|
...resetsAt !== void 0 ? { resetsAt } : {},
|
|
992
|
-
remainingSeconds:
|
|
1650
|
+
remainingSeconds: secondsUntil6(resetsAt, now),
|
|
993
1651
|
state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
|
|
994
1652
|
};
|
|
995
1653
|
}
|
|
996
1654
|
var OpenCodeGoAllowanceCollector = class {
|
|
997
|
-
constructor(credentials, store =
|
|
1655
|
+
constructor(credentials, store = getSharedAccountAllowanceStore6(), fetchImpl = (url, init, accountId) => fetchUpstream6(url, init, { providerId: "opencodego", accountId, redactBodies: true }), now = Date.now) {
|
|
998
1656
|
this.credentials = credentials;
|
|
999
1657
|
this.store = store;
|
|
1000
1658
|
this.fetchImpl = fetchImpl;
|
|
@@ -1099,7 +1757,7 @@ function codexUnavailable(accountId, now) {
|
|
|
1099
1757
|
};
|
|
1100
1758
|
}
|
|
1101
1759
|
var AccountAllowanceService = class {
|
|
1102
|
-
constructor(credentials, store =
|
|
1760
|
+
constructor(credentials, store = getSharedAccountAllowanceStore7(), collector, codexCollector, kimiCollector, opencodegoCollector, grokCollector, copilotCollector, now = Date.now) {
|
|
1103
1761
|
this.credentials = credentials;
|
|
1104
1762
|
this.store = store;
|
|
1105
1763
|
this.now = now;
|
|
@@ -1107,6 +1765,8 @@ var AccountAllowanceService = class {
|
|
|
1107
1765
|
this.codexCollector = codexCollector ?? new CodexAllowanceCollector(credentials, store);
|
|
1108
1766
|
this.kimiCollector = kimiCollector ?? new KimiAllowanceCollector(credentials, store);
|
|
1109
1767
|
this.opencodegoCollector = opencodegoCollector ?? new OpenCodeGoAllowanceCollector(credentials, store);
|
|
1768
|
+
this.grokCollector = grokCollector ?? new GrokAllowanceCollector(credentials, store);
|
|
1769
|
+
this.copilotCollector = copilotCollector ?? new CopilotAllowanceCollector(credentials, store);
|
|
1110
1770
|
}
|
|
1111
1771
|
credentials;
|
|
1112
1772
|
store;
|
|
@@ -1114,6 +1774,8 @@ var AccountAllowanceService = class {
|
|
|
1114
1774
|
claudeCollector;
|
|
1115
1775
|
codexCollector;
|
|
1116
1776
|
kimiCollector;
|
|
1777
|
+
grokCollector;
|
|
1778
|
+
copilotCollector;
|
|
1117
1779
|
opencodegoCollector;
|
|
1118
1780
|
/**
|
|
1119
1781
|
* Read all/filtered snapshots. Claude's and Codex's five-minute caches are
|
|
@@ -1148,11 +1810,23 @@ var AccountAllowanceService = class {
|
|
|
1148
1810
|
(account) => !filter.accountId || account.id === filter.accountId
|
|
1149
1811
|
);
|
|
1150
1812
|
if (wantsOpenCodeGo) await this.opencodegoCollector.collectMany(opencodegoAccounts);
|
|
1813
|
+
const wantsGrok = !filter.providerId || filter.providerId === "grok";
|
|
1814
|
+
const grokAccounts = (config.grokAccounts ?? []).filter(
|
|
1815
|
+
(account) => !filter.accountId || account.id === filter.accountId
|
|
1816
|
+
);
|
|
1817
|
+
if (wantsGrok) await this.grokCollector.collectMany(grokAccounts);
|
|
1818
|
+
const wantsCopilot = !filter.providerId || filter.providerId === "copilot";
|
|
1819
|
+
const copilotAccounts = (config.copilotAccounts ?? []).filter(
|
|
1820
|
+
(account) => !filter.accountId || account.id === filter.accountId
|
|
1821
|
+
);
|
|
1822
|
+
if (wantsCopilot) await this.copilotCollector.collectMany(copilotAccounts);
|
|
1151
1823
|
const known = /* @__PURE__ */ new Set();
|
|
1152
1824
|
if (wantsClaude) for (const account of claudeAccounts) known.add(`claude\0${account.id}`);
|
|
1153
1825
|
if (wantsCodex) for (const account of codexAccounts) known.add(`codex\0${account.id}`);
|
|
1154
1826
|
if (wantsKimi) for (const account of kimiAccounts) known.add(`kimi\0${account.id}`);
|
|
1155
1827
|
if (wantsOpenCodeGo) for (const account of opencodegoAccounts) known.add(`opencodego\0${account.id}`);
|
|
1828
|
+
if (wantsGrok) for (const account of grokAccounts) known.add(`grok\0${account.id}`);
|
|
1829
|
+
if (wantsCopilot) for (const account of copilotAccounts) known.add(`copilot\0${account.id}`);
|
|
1156
1830
|
return this.store.list(filter).filter((snapshot) => known.has(`${snapshot.providerId}\0${snapshot.accountId}`));
|
|
1157
1831
|
}
|
|
1158
1832
|
knownAccounts(config) {
|
|
@@ -1160,7 +1834,9 @@ var AccountAllowanceService = class {
|
|
|
1160
1834
|
...(config.claudeAccounts ?? []).map((account) => ({ providerId: "claude", accountId: account.id })),
|
|
1161
1835
|
...(config.codexAccounts ?? []).map((account) => ({ providerId: "codex", accountId: account.id })),
|
|
1162
1836
|
...(config.kimiAccounts ?? []).map((account) => ({ providerId: "kimi", accountId: account.id })),
|
|
1163
|
-
...(config.opencodegoAccounts ?? []).map((account) => ({ providerId: "opencodego", accountId: account.id }))
|
|
1837
|
+
...(config.opencodegoAccounts ?? []).map((account) => ({ providerId: "opencodego", accountId: account.id })),
|
|
1838
|
+
...(config.grokAccounts ?? []).map((account) => ({ providerId: "grok", accountId: account.id })),
|
|
1839
|
+
...(config.copilotAccounts ?? []).map((account) => ({ providerId: "copilot", accountId: account.id }))
|
|
1164
1840
|
];
|
|
1165
1841
|
}
|
|
1166
1842
|
/** Force-refresh Claude usage for one account or every stored Claude account. */
|
|
@@ -1203,6 +1879,24 @@ var AccountAllowanceService = class {
|
|
|
1203
1879
|
);
|
|
1204
1880
|
return this.kimiCollector.collectMany(accounts, { force: true });
|
|
1205
1881
|
}
|
|
1882
|
+
/** Force-refresh Copilot usage (copilot_internal/user) for one/all accounts. */
|
|
1883
|
+
async refreshCopilot(accountId) {
|
|
1884
|
+
const config = await this.credentials.getFullConfig();
|
|
1885
|
+
this.store.pruneToKnownAccounts(this.knownAccounts(config));
|
|
1886
|
+
const accounts = (config.copilotAccounts ?? []).filter(
|
|
1887
|
+
(account) => !accountId || account.id === accountId
|
|
1888
|
+
);
|
|
1889
|
+
return this.copilotCollector.collectMany(accounts, { force: true });
|
|
1890
|
+
}
|
|
1891
|
+
/** Force-refresh Grok usage (CLI billing proxy) for one/all accounts. */
|
|
1892
|
+
async refreshGrok(accountId) {
|
|
1893
|
+
const config = await this.credentials.getFullConfig();
|
|
1894
|
+
this.store.pruneToKnownAccounts(this.knownAccounts(config));
|
|
1895
|
+
const accounts = (config.grokAccounts ?? []).filter(
|
|
1896
|
+
(account) => !accountId || account.id === accountId
|
|
1897
|
+
);
|
|
1898
|
+
return this.grokCollector.collectMany(accounts, { force: true });
|
|
1899
|
+
}
|
|
1206
1900
|
/**
|
|
1207
1901
|
* Keep Claude + Codex + Kimi snapshots warm for allowance-aware routing. All
|
|
1208
1902
|
* collectors preserve their cache + per-account in-flight coalescing; a tick
|
|
@@ -1217,6 +1911,8 @@ var AccountAllowanceService = class {
|
|
|
1217
1911
|
await this.codexCollector.collectMany(config.codexAccounts ?? [], { refreshAheadMs });
|
|
1218
1912
|
await this.kimiCollector.collectMany(config.kimiAccounts ?? [], { refreshAheadMs });
|
|
1219
1913
|
await this.opencodegoCollector.collectMany(config.opencodegoAccounts ?? [], { refreshAheadMs });
|
|
1914
|
+
await this.grokCollector.collectMany(config.grokAccounts ?? [], { refreshAheadMs });
|
|
1915
|
+
await this.copilotCollector.collectMany(config.copilotAccounts ?? [], { refreshAheadMs });
|
|
1220
1916
|
}
|
|
1221
1917
|
/** Remove a cache row as soon as an account is deleted by the admin path. */
|
|
1222
1918
|
removeAccountSnapshot(providerId, accountId) {
|
|
@@ -1653,7 +2349,8 @@ import {
|
|
|
1653
2349
|
} from "@omnicross/contracts/image-generation-types";
|
|
1654
2350
|
import { getSharedAccountAllowanceScheduling as getSharedAccountAllowanceScheduling2 } from "@omnicross/core/pipeline/AccountAllowanceScheduling";
|
|
1655
2351
|
import { getSharedAccountHealth } from "@omnicross/core/pipeline/SubscriptionAccountHealth";
|
|
1656
|
-
import { fetchUpstream as
|
|
2352
|
+
import { fetchUpstream as fetchUpstream7 } from "@omnicross/core/pipeline/upstreamFetch";
|
|
2353
|
+
import { mergeExtraHeaders } from "@omnicross/core";
|
|
1657
2354
|
|
|
1658
2355
|
// src/image-generation/imagesConfigValidation.ts
|
|
1659
2356
|
import { validateImagesServerConfig } from "@omnicross/core/outbound-api";
|
|
@@ -1966,6 +2663,7 @@ async function applyServerConfigTransaction(current, next, deps) {
|
|
|
1966
2663
|
|
|
1967
2664
|
// src/config.ts
|
|
1968
2665
|
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
2666
|
+
import { EXTRA_HEADER_RESERVED_NAMES } from "@omnicross/core";
|
|
1969
2667
|
|
|
1970
2668
|
// src/secrets/envelope.ts
|
|
1971
2669
|
import { createCipheriv, createDecipheriv, randomBytes as randomBytes2 } from "crypto";
|
|
@@ -2377,6 +3075,18 @@ var FORMAT_AXIS_TRANSFORMERS = [
|
|
|
2377
3075
|
"openai-response",
|
|
2378
3076
|
"gemini-code-assist"
|
|
2379
3077
|
];
|
|
3078
|
+
function validateExtraHeaders(raw) {
|
|
3079
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
3080
|
+
const reserved = EXTRA_HEADER_RESERVED_NAMES;
|
|
3081
|
+
const out = {};
|
|
3082
|
+
for (const [name, value] of Object.entries(raw)) {
|
|
3083
|
+
if (!name.trim()) continue;
|
|
3084
|
+
if (typeof value !== "string") continue;
|
|
3085
|
+
if (reserved.has(name.toLowerCase())) continue;
|
|
3086
|
+
out[name] = value;
|
|
3087
|
+
}
|
|
3088
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
3089
|
+
}
|
|
2380
3090
|
function validateApiKeys(raw) {
|
|
2381
3091
|
if (!Array.isArray(raw)) return void 0;
|
|
2382
3092
|
const out = [];
|
|
@@ -2590,6 +3300,9 @@ function validateProvider(raw, index) {
|
|
|
2590
3300
|
apiVersion,
|
|
2591
3301
|
maxConcurrency,
|
|
2592
3302
|
modelsEndpoint,
|
|
3303
|
+
// Static extra headers: load-guard (reserved names dropped), collapse-to-
|
|
3304
|
+
// undefined; enforced by the outbound header funnel + admin probes.
|
|
3305
|
+
extraHeaders: validateExtraHeaders(p["extraHeaders"]),
|
|
2593
3306
|
// Provider transformer config (app-parity child 5): load-guard, collapse-to-
|
|
2594
3307
|
// undefined; non-secret; ENFORCED via resolveTransformerChain (parity-2 child 2).
|
|
2595
3308
|
// Format-axis entries are stripped by `migrateFormatAxis` — `use[]` is the
|
|
@@ -3559,7 +4272,8 @@ function listMappablePresets() {
|
|
|
3559
4272
|
description: preset.description,
|
|
3560
4273
|
features: preset.features,
|
|
3561
4274
|
website: preset.website,
|
|
3562
|
-
modelsEndpoint: preset.modelsEndpoint
|
|
4275
|
+
modelsEndpoint: preset.modelsEndpoint,
|
|
4276
|
+
extraHeaders: preset.extraHeaders
|
|
3563
4277
|
});
|
|
3564
4278
|
}
|
|
3565
4279
|
return { mappable, excluded };
|
|
@@ -3731,7 +4445,9 @@ var VALID_PROVIDER_IDS = [
|
|
|
3731
4445
|
"codex",
|
|
3732
4446
|
"gemini",
|
|
3733
4447
|
"opencodego",
|
|
3734
|
-
"kimi"
|
|
4448
|
+
"kimi",
|
|
4449
|
+
"grok",
|
|
4450
|
+
"copilot"
|
|
3735
4451
|
];
|
|
3736
4452
|
function asSubscriptionProviderId(id) {
|
|
3737
4453
|
return VALID_PROVIDER_IDS.includes(id) ? id : null;
|
|
@@ -3879,6 +4595,40 @@ function validateKimi(body) {
|
|
|
3879
4595
|
copyOptional(out, body, ["accessToken", "refreshToken", "expiresAt", "accountId", "deviceId", "lastRefreshedAt", "errorMessage"]);
|
|
3880
4596
|
return out;
|
|
3881
4597
|
}
|
|
4598
|
+
function validateGrok(body) {
|
|
4599
|
+
const authMethod = str(body["authMethod"]);
|
|
4600
|
+
const status = str(body["status"]);
|
|
4601
|
+
if (!authMethod || !OAUTH_AUTH_METHODS.has(authMethod)) return null;
|
|
4602
|
+
if (!status || !TOKEN_STATUSES.has(status)) return null;
|
|
4603
|
+
const out = {
|
|
4604
|
+
authMethod,
|
|
4605
|
+
status
|
|
4606
|
+
};
|
|
4607
|
+
copyOptional(out, body, ["accessToken", "refreshToken", "expiresAt", "accountId", "lastRefreshedAt", "errorMessage"]);
|
|
4608
|
+
return out;
|
|
4609
|
+
}
|
|
4610
|
+
function validateCopilot(body) {
|
|
4611
|
+
const authMethod = str(body["authMethod"]);
|
|
4612
|
+
const status = str(body["status"]);
|
|
4613
|
+
if (!authMethod || !OAUTH_AUTH_METHODS.has(authMethod)) return null;
|
|
4614
|
+
if (!status || !TOKEN_STATUSES.has(status)) return null;
|
|
4615
|
+
const out = {
|
|
4616
|
+
authMethod,
|
|
4617
|
+
status
|
|
4618
|
+
};
|
|
4619
|
+
copyOptional(out, body, [
|
|
4620
|
+
"accessToken",
|
|
4621
|
+
"refreshToken",
|
|
4622
|
+
"expiresAt",
|
|
4623
|
+
"accountId",
|
|
4624
|
+
"email",
|
|
4625
|
+
"apiEndpoint",
|
|
4626
|
+
"enterpriseUrl",
|
|
4627
|
+
"lastRefreshedAt",
|
|
4628
|
+
"errorMessage"
|
|
4629
|
+
]);
|
|
4630
|
+
return out;
|
|
4631
|
+
}
|
|
3882
4632
|
function validateOpenCodeGo(body) {
|
|
3883
4633
|
const authMethod = str(body["authMethod"]);
|
|
3884
4634
|
const status = str(body["status"]);
|
|
@@ -3916,6 +4666,10 @@ function validateTokenBody(providerId, body) {
|
|
|
3916
4666
|
return validateOpenCodeGo(body);
|
|
3917
4667
|
case "kimi":
|
|
3918
4668
|
return validateKimi(body);
|
|
4669
|
+
case "grok":
|
|
4670
|
+
return validateGrok(body);
|
|
4671
|
+
case "copilot":
|
|
4672
|
+
return validateCopilot(body);
|
|
3919
4673
|
default:
|
|
3920
4674
|
return null;
|
|
3921
4675
|
}
|
|
@@ -3945,12 +4699,12 @@ async function statusEntryFor(reader, providerId) {
|
|
|
3945
4699
|
|
|
3946
4700
|
// src/admin/accountsOAuth.ts
|
|
3947
4701
|
var OAUTH_HTTP_PROVIDERS = /* @__PURE__ */ new Set(["claude", "gemini"]);
|
|
3948
|
-
function
|
|
4702
|
+
function err5(status, message) {
|
|
3949
4703
|
return { status, body: { error: { type: "admin_api_error", message } } };
|
|
3950
4704
|
}
|
|
3951
4705
|
function handleOAuthStart(providerId, deps) {
|
|
3952
4706
|
if (!OAUTH_HTTP_PROVIDERS.has(providerId)) {
|
|
3953
|
-
return
|
|
4707
|
+
return err5(400, `oauth not available for provider '${providerId}'`);
|
|
3954
4708
|
}
|
|
3955
4709
|
const flow = providerId === "claude" ? claudeOAuth : geminiOAuth;
|
|
3956
4710
|
const { authUrl, codeVerifier, state } = flow.generateAuthParams();
|
|
@@ -3959,23 +4713,23 @@ function handleOAuthStart(providerId, deps) {
|
|
|
3959
4713
|
}
|
|
3960
4714
|
async function handleOAuthComplete(providerId, body, deps) {
|
|
3961
4715
|
if (!OAUTH_HTTP_PROVIDERS.has(providerId)) {
|
|
3962
|
-
return
|
|
4716
|
+
return err5(400, `oauth not available for provider '${providerId}'`);
|
|
3963
4717
|
}
|
|
3964
4718
|
const sessionId = typeof body["sessionId"] === "string" ? body["sessionId"] : "";
|
|
3965
4719
|
const rawCode = typeof body["code"] === "string" ? body["code"] : "";
|
|
3966
|
-
if (!sessionId) return
|
|
3967
|
-
if (!rawCode) return
|
|
4720
|
+
if (!sessionId) return err5(400, "oauth complete requires { sessionId }");
|
|
4721
|
+
if (!rawCode) return err5(400, "oauth complete requires { code }");
|
|
3968
4722
|
const session = deps.oauthSessions.peek(sessionId);
|
|
3969
|
-
if (!session) return
|
|
4723
|
+
if (!session) return err5(410, "oauth session is unknown, expired, or already used");
|
|
3970
4724
|
if (session.providerId !== providerId) {
|
|
3971
|
-
return
|
|
4725
|
+
return err5(400, `oauth session does not match provider '${providerId}'`);
|
|
3972
4726
|
}
|
|
3973
4727
|
let code = rawCode.trim();
|
|
3974
4728
|
if (providerId === "claude") {
|
|
3975
4729
|
const [splitCode, pastedState] = code.split("#");
|
|
3976
|
-
if (!splitCode) return
|
|
4730
|
+
if (!splitCode) return err5(400, "no authorization code was provided");
|
|
3977
4731
|
if (pastedState && pastedState !== session.state) {
|
|
3978
|
-
return
|
|
4732
|
+
return err5(400, "oauth state did not match (possible CSRF) \u2014 aborting");
|
|
3979
4733
|
}
|
|
3980
4734
|
code = splitCode;
|
|
3981
4735
|
}
|
|
@@ -3985,7 +4739,7 @@ async function handleOAuthComplete(providerId, body, deps) {
|
|
|
3985
4739
|
block = providerId === "claude" ? await exchangeClaude(code, session.codeVerifier, session.state, exchangeFetch) : await exchangeGemini(code, session.codeVerifier, exchangeFetch);
|
|
3986
4740
|
} catch (exchangeError) {
|
|
3987
4741
|
const reason = exchangeError instanceof Error ? exchangeError.message : "token exchange failed";
|
|
3988
|
-
return
|
|
4742
|
+
return err5(502, `oauth token exchange failed for '${providerId}': ${reason}`);
|
|
3989
4743
|
}
|
|
3990
4744
|
deps.oauthSessions.consume(sessionId);
|
|
3991
4745
|
const label = typeof body["label"] === "string" && body["label"].trim() ? body["label"].trim() : void 0;
|
|
@@ -4323,8 +5077,8 @@ function errBody(message) {
|
|
|
4323
5077
|
return { error: { type: "admin_api_error", message } };
|
|
4324
5078
|
}
|
|
4325
5079
|
var defaultCommandRunner = (command) => new Promise((resolve10) => {
|
|
4326
|
-
exec(command, { timeout: 18e4 }, (
|
|
4327
|
-
if (
|
|
5080
|
+
exec(command, { timeout: 18e4 }, (err8, _stdout, stderr) => {
|
|
5081
|
+
if (err8) resolve10({ ok: false, error: stderr.trim() || err8.message });
|
|
4328
5082
|
else resolve10({ ok: true });
|
|
4329
5083
|
});
|
|
4330
5084
|
});
|
|
@@ -4370,8 +5124,8 @@ async function handleCliLaunch(cli, body, ctx) {
|
|
|
4370
5124
|
providerId: typeof body["providerId"] === "string" ? body["providerId"] : void 0,
|
|
4371
5125
|
model: typeof body["model"] === "string" ? body["model"] : void 0
|
|
4372
5126
|
});
|
|
4373
|
-
} catch (
|
|
4374
|
-
return { status: 400, body: errBody(
|
|
5127
|
+
} catch (err8) {
|
|
5128
|
+
return { status: 400, body: errBody(err8 instanceof Error ? err8.message : "no launch target") };
|
|
4375
5129
|
}
|
|
4376
5130
|
const id = randomUUID2();
|
|
4377
5131
|
let leaseId2;
|
|
@@ -4399,9 +5153,9 @@ async function handleCliLaunch(cli, body, ctx) {
|
|
|
4399
5153
|
} else {
|
|
4400
5154
|
launch = await buildLaunchEnv(cli, ctx.llmConfig, target);
|
|
4401
5155
|
}
|
|
4402
|
-
} catch (
|
|
4403
|
-
const status =
|
|
4404
|
-
return { status, body: errBody(
|
|
5156
|
+
} catch (err8) {
|
|
5157
|
+
const status = err8 instanceof RouteLeaseError2 ? err8.status : 400;
|
|
5158
|
+
return { status, body: errBody(err8 instanceof Error ? err8.message : "failed to build launch env") };
|
|
4405
5159
|
}
|
|
4406
5160
|
const cwd = typeof body["cwd"] === "string" && body["cwd"].trim() ? body["cwd"].trim() : void 0;
|
|
4407
5161
|
const opener = ctx.opener ?? defaultTerminalOpener;
|
|
@@ -4429,9 +5183,9 @@ async function handleCliLaunch(cli, body, ctx) {
|
|
|
4429
5183
|
onFailure: onSessionEnd
|
|
4430
5184
|
});
|
|
4431
5185
|
if (cleanup) openerCleanup = cleanup;
|
|
4432
|
-
} catch (
|
|
5186
|
+
} catch (err8) {
|
|
4433
5187
|
onSessionEnd();
|
|
4434
|
-
return { status: 500, body: errBody(
|
|
5188
|
+
return { status: 500, body: errBody(err8 instanceof Error ? err8.message : "failed to open terminal") };
|
|
4435
5189
|
}
|
|
4436
5190
|
if (ended) {
|
|
4437
5191
|
openerCleanup?.();
|
|
@@ -4980,7 +5734,7 @@ async function handleSearchQuery(req, res, deps) {
|
|
|
4980
5734
|
// src/admin/searchAdminView.ts
|
|
4981
5735
|
var API_KEY_PROVIDERS = /* @__PURE__ */ new Set(["tavily", "jina", "zhipu", "z.ai"]);
|
|
4982
5736
|
var BASIC_AUTH_PROVIDERS = /* @__PURE__ */ new Set(["searxng"]);
|
|
4983
|
-
function
|
|
5737
|
+
function isRecord4(value) {
|
|
4984
5738
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
4985
5739
|
}
|
|
4986
5740
|
function redactSearchServerConfig(search) {
|
|
@@ -5030,13 +5784,13 @@ function resolveSecretField(entry, field, stored) {
|
|
|
5030
5784
|
else delete entry[field];
|
|
5031
5785
|
}
|
|
5032
5786
|
function preserveSearchSecrets(incoming, current) {
|
|
5033
|
-
if (!
|
|
5787
|
+
if (!isRecord4(incoming)) return incoming;
|
|
5034
5788
|
const section = { ...incoming };
|
|
5035
5789
|
const providersValue = section["providers"];
|
|
5036
|
-
if (!
|
|
5790
|
+
if (!isRecord4(providersValue)) return section;
|
|
5037
5791
|
const providers = {};
|
|
5038
5792
|
for (const [id, entryValue] of Object.entries(providersValue)) {
|
|
5039
|
-
if (!
|
|
5793
|
+
if (!isRecord4(entryValue)) {
|
|
5040
5794
|
providers[id] = entryValue;
|
|
5041
5795
|
continue;
|
|
5042
5796
|
}
|
|
@@ -5114,7 +5868,7 @@ function parseKeyPolicyBody(body) {
|
|
|
5114
5868
|
var ENDPOINTS = /* @__PURE__ */ new Set(["chat", "responses", "messages", "gemini"]);
|
|
5115
5869
|
var TARGET_KINDS = /* @__PURE__ */ new Set(["account", "account-group", "account-pool", "provider"]);
|
|
5116
5870
|
var FALLBACKS = /* @__PURE__ */ new Set(["next", "fail", "global"]);
|
|
5117
|
-
function
|
|
5871
|
+
function isRecord5(value) {
|
|
5118
5872
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
5119
5873
|
}
|
|
5120
5874
|
function nonBlank(value) {
|
|
@@ -5134,7 +5888,7 @@ function validateGatewayBindingsSegment(patch) {
|
|
|
5134
5888
|
const ids = /* @__PURE__ */ new Set();
|
|
5135
5889
|
raw.forEach((entry, index) => {
|
|
5136
5890
|
const path2 = `bindings[${index}]`;
|
|
5137
|
-
if (!
|
|
5891
|
+
if (!isRecord5(entry)) {
|
|
5138
5892
|
errors.push(`${path2} must be an object`);
|
|
5139
5893
|
return;
|
|
5140
5894
|
}
|
|
@@ -5163,12 +5917,12 @@ function validateGatewayBindingsSegment(patch) {
|
|
|
5163
5917
|
} else if (entry.modelMappings.length > 100) {
|
|
5164
5918
|
errors.push(`${path2}.modelMappings cannot contain more than 100 entries`);
|
|
5165
5919
|
} else if (entry.modelMappings.some(
|
|
5166
|
-
(mapping) => !
|
|
5920
|
+
(mapping) => !isRecord5(mapping) || !nonBlank(mapping.source) || !nonBlank(mapping.target)
|
|
5167
5921
|
)) {
|
|
5168
5922
|
errors.push(`${path2}.modelMappings must contain non-empty source and target strings`);
|
|
5169
5923
|
}
|
|
5170
5924
|
}
|
|
5171
|
-
if (!
|
|
5925
|
+
if (!isRecord5(entry.target) || !TARGET_KINDS.has(String(entry.target.kind))) {
|
|
5172
5926
|
errors.push(`${path2}.target is invalid`);
|
|
5173
5927
|
} else {
|
|
5174
5928
|
if (!nonBlank(entry.target.providerId)) errors.push(`${path2}.target.providerId is required`);
|
|
@@ -5183,7 +5937,7 @@ function validateGatewayBindingsSegment(patch) {
|
|
|
5183
5937
|
}
|
|
5184
5938
|
}
|
|
5185
5939
|
if (entry.modelMap !== void 0) {
|
|
5186
|
-
if (!
|
|
5940
|
+
if (!isRecord5(entry.modelMap) || Object.values(entry.modelMap).some((value) => typeof value !== "string")) {
|
|
5187
5941
|
errors.push(`${path2}.modelMap must contain string values`);
|
|
5188
5942
|
}
|
|
5189
5943
|
}
|
|
@@ -5494,7 +6248,9 @@ var PROVIDER_KEYS = {
|
|
|
5494
6248
|
accounts: "opencodegoAccounts",
|
|
5495
6249
|
active: "activeOpencodegoAccountId"
|
|
5496
6250
|
},
|
|
5497
|
-
kimi: { block: "kimi", accounts: "kimiAccounts", active: "activeKimiAccountId" }
|
|
6251
|
+
kimi: { block: "kimi", accounts: "kimiAccounts", active: "activeKimiAccountId" },
|
|
6252
|
+
grok: { block: "grok", accounts: "grokAccounts", active: "activeGrokAccountId" },
|
|
6253
|
+
copilot: { block: "copilot", accounts: "copilotAccounts", active: "activeCopilotAccountId" }
|
|
5498
6254
|
};
|
|
5499
6255
|
function clone(value) {
|
|
5500
6256
|
return JSON.parse(JSON.stringify(value));
|
|
@@ -6016,7 +6772,7 @@ async function applyImport(packString, passphrase, mode, deps, parseProviderInpu
|
|
|
6016
6772
|
}
|
|
6017
6773
|
|
|
6018
6774
|
// src/admin/adminMigration.ts
|
|
6019
|
-
function
|
|
6775
|
+
function err6(status, message) {
|
|
6020
6776
|
return { status, body: { error: { type: "admin_api_error", message } } };
|
|
6021
6777
|
}
|
|
6022
6778
|
async function handleExport(body, deps) {
|
|
@@ -6026,30 +6782,30 @@ async function handleExport(body, deps) {
|
|
|
6026
6782
|
return { status: 200, body: { pack, version: BUNDLE_VERSION } };
|
|
6027
6783
|
} catch (error) {
|
|
6028
6784
|
if (error instanceof WeakPassphraseError) {
|
|
6029
|
-
return
|
|
6785
|
+
return err6(400, error.message);
|
|
6030
6786
|
}
|
|
6031
|
-
return
|
|
6787
|
+
return err6(500, "failed to build the migration pack");
|
|
6032
6788
|
}
|
|
6033
6789
|
}
|
|
6034
6790
|
async function handleImport(body, deps) {
|
|
6035
6791
|
const blob = typeof body["blob"] === "string" ? body["blob"] : "";
|
|
6036
6792
|
const passphrase = typeof body["passphrase"] === "string" ? body["passphrase"] : "";
|
|
6037
6793
|
const mode = body["mode"] === "overwrite" ? "overwrite" : "merge";
|
|
6038
|
-
if (!blob) return
|
|
6794
|
+
if (!blob) return err6(400, "import requires { blob }");
|
|
6039
6795
|
try {
|
|
6040
6796
|
const counts = await applyImport(blob, passphrase, mode, deps, deps.parseProviderInput);
|
|
6041
6797
|
return { status: 200, body: counts };
|
|
6042
6798
|
} catch (error) {
|
|
6043
6799
|
if (error instanceof WeakPassphraseError) {
|
|
6044
|
-
return
|
|
6800
|
+
return err6(400, error.message);
|
|
6045
6801
|
}
|
|
6046
|
-
return
|
|
6802
|
+
return err6(400, error instanceof Error ? error.message : "import failed");
|
|
6047
6803
|
}
|
|
6048
6804
|
}
|
|
6049
6805
|
|
|
6050
6806
|
// src/admin/usagePricing.ts
|
|
6051
6807
|
import { getSharedUsageThroughputTracker } from "@omnicross/core/usage";
|
|
6052
|
-
var
|
|
6808
|
+
var err7 = (status, message) => ({
|
|
6053
6809
|
status,
|
|
6054
6810
|
body: { error: { type: "admin_api_error", message } }
|
|
6055
6811
|
});
|
|
@@ -6062,7 +6818,7 @@ function parseRange(query2) {
|
|
|
6062
6818
|
const startTs = parseFiniteInt(query2.get("startTs"));
|
|
6063
6819
|
const endTs = parseFiniteInt(query2.get("endTs"));
|
|
6064
6820
|
if (startTs === null || endTs === null) {
|
|
6065
|
-
return
|
|
6821
|
+
return err7(400, "startTs and endTs are required finite-integer unix-millis query params");
|
|
6066
6822
|
}
|
|
6067
6823
|
return { startTs, endTs };
|
|
6068
6824
|
}
|
|
@@ -6087,14 +6843,14 @@ async function handleUsageGet(view, query2, deps) {
|
|
|
6087
6843
|
case "timeseries": {
|
|
6088
6844
|
const bucket = query2.get("bucket");
|
|
6089
6845
|
if (bucket !== "hour" && bucket !== "day" && bucket !== "month") {
|
|
6090
|
-
return
|
|
6846
|
+
return err7(400, "bucket must be one of 'hour', 'day', 'month'");
|
|
6091
6847
|
}
|
|
6092
6848
|
const now = Date.now();
|
|
6093
6849
|
const clamped = { startTs: range.startTs, endTs: Math.min(range.endTs, now) };
|
|
6094
6850
|
if (clamped.startTs < clamped.endTs) {
|
|
6095
6851
|
const projected = Math.ceil((clamped.endTs - clamped.startTs) / BUCKET_SPAN_MS[bucket]) + 1;
|
|
6096
6852
|
if (projected > MAX_TIMESERIES_BUCKETS) {
|
|
6097
|
-
return
|
|
6853
|
+
return err7(
|
|
6098
6854
|
400,
|
|
6099
6855
|
`requested range projects ~${projected} '${bucket}' buckets (max ${MAX_TIMESERIES_BUCKETS}); narrow the range or use a coarser bucket`
|
|
6100
6856
|
);
|
|
@@ -6117,7 +6873,7 @@ async function handleUsageGet(view, query2, deps) {
|
|
|
6117
6873
|
};
|
|
6118
6874
|
}
|
|
6119
6875
|
default:
|
|
6120
|
-
return
|
|
6876
|
+
return err7(404, `unknown usage view '${view ?? ""}'`);
|
|
6121
6877
|
}
|
|
6122
6878
|
}
|
|
6123
6879
|
function poolKeyLabels(cfg) {
|
|
@@ -6166,7 +6922,7 @@ async function handlePricingList(deps) {
|
|
|
6166
6922
|
async function handlePricingUpsert(body, deps) {
|
|
6167
6923
|
const input = parsePricingEntryInput(body);
|
|
6168
6924
|
if (!input) {
|
|
6169
|
-
return
|
|
6925
|
+
return err7(400, "invalid pricing entry (providerId, modelId, finite numeric inputPricePer1m/outputPricePer1m required)");
|
|
6170
6926
|
}
|
|
6171
6927
|
const entry = await deps.pricingEngine.upsertManual(input);
|
|
6172
6928
|
return { status: 200, body: { entry } };
|
|
@@ -6175,7 +6931,7 @@ async function handlePricingDelete(query2, deps) {
|
|
|
6175
6931
|
const providerId = query2.get("providerId")?.trim() ?? "";
|
|
6176
6932
|
const modelId = query2.get("modelId")?.trim() ?? "";
|
|
6177
6933
|
if (!providerId || !modelId) {
|
|
6178
|
-
return
|
|
6934
|
+
return err7(400, "delete requires providerId and modelId query params");
|
|
6179
6935
|
}
|
|
6180
6936
|
const deleted = await deps.pricingStore.delete(providerId, modelId);
|
|
6181
6937
|
if (deleted) await deps.pricingEngine.invalidateCache();
|
|
@@ -6195,13 +6951,13 @@ async function handlePricingFetchLatest(deps) {
|
|
|
6195
6951
|
}
|
|
6196
6952
|
};
|
|
6197
6953
|
} catch (e) {
|
|
6198
|
-
return
|
|
6954
|
+
return err7(502, `pricing-source fetch failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
6199
6955
|
}
|
|
6200
6956
|
}
|
|
6201
6957
|
async function handlePricingResolveConflicts(body, deps) {
|
|
6202
6958
|
const raw = body["resolutions"];
|
|
6203
6959
|
if (!Array.isArray(raw)) {
|
|
6204
|
-
return
|
|
6960
|
+
return err7(400, "resolve-conflicts requires { resolutions: [...] }");
|
|
6205
6961
|
}
|
|
6206
6962
|
const currentRows = await deps.pricingStore.getAll();
|
|
6207
6963
|
const userEditedKeys = new Set(
|
|
@@ -6211,21 +6967,21 @@ async function handlePricingResolveConflicts(body, deps) {
|
|
|
6211
6967
|
const pendingIncoming = /* @__PURE__ */ new Map();
|
|
6212
6968
|
let staleCount = 0;
|
|
6213
6969
|
for (const item of raw) {
|
|
6214
|
-
if (!item || typeof item !== "object") return
|
|
6970
|
+
if (!item || typeof item !== "object") return err7(400, "invalid resolution entry");
|
|
6215
6971
|
const r = item;
|
|
6216
6972
|
const action = r["action"];
|
|
6217
6973
|
if (action !== "overwrite" && action !== "skip") {
|
|
6218
|
-
return
|
|
6974
|
+
return err7(400, "resolution action must be 'overwrite' or 'skip'");
|
|
6219
6975
|
}
|
|
6220
6976
|
const providerId = typeof r["providerId"] === "string" && r["providerId"].trim() ? r["providerId"].trim() : "";
|
|
6221
6977
|
const modelId = typeof r["modelId"] === "string" && r["modelId"].trim() ? r["modelId"].trim() : "";
|
|
6222
6978
|
if (!providerId || !modelId) {
|
|
6223
|
-
return
|
|
6979
|
+
return err7(400, "each resolution requires top-level providerId and modelId");
|
|
6224
6980
|
}
|
|
6225
6981
|
const incoming = parsePricingEntryInput(r["incoming"]);
|
|
6226
|
-
if (!incoming) return
|
|
6982
|
+
if (!incoming) return err7(400, "each resolution must echo a valid incoming pricing entry");
|
|
6227
6983
|
if (incoming.providerId !== providerId || incoming.modelId !== modelId) {
|
|
6228
|
-
return
|
|
6984
|
+
return err7(400, "resolution providerId/modelId must match the echoed incoming entry");
|
|
6229
6985
|
}
|
|
6230
6986
|
const key = `${providerId}::${modelId}`;
|
|
6231
6987
|
if (action === "overwrite" && !userEditedKeys.has(key)) {
|
|
@@ -6270,7 +7026,7 @@ function query(req) {
|
|
|
6270
7026
|
}
|
|
6271
7027
|
function allowanceProvider(value) {
|
|
6272
7028
|
if (!value) return void 0;
|
|
6273
|
-
return value === "claude" || value === "codex" || value === "kimi" || value === "opencodego" ? value : null;
|
|
7029
|
+
return value === "claude" || value === "codex" || value === "kimi" || value === "opencodego" || value === "grok" || value === "copilot" ? value : null;
|
|
6274
7030
|
}
|
|
6275
7031
|
async function handleAccountAllowanceApi(req, res, method, rest, service) {
|
|
6276
7032
|
if (!service) return writeError2(res, 501, "account allowance service is not available");
|
|
@@ -6285,7 +7041,7 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
|
|
|
6285
7041
|
const pathProvider = rest.length >= 2 ? rest[0] : null;
|
|
6286
7042
|
const providerId = allowanceProvider(pathProvider ?? params.get("providerId") ?? params.get("provider"));
|
|
6287
7043
|
if (providerId === null) {
|
|
6288
|
-
return writeError2(res, 400, "providerId must be claude, codex, kimi, or
|
|
7044
|
+
return writeError2(res, 400, "providerId must be claude, codex, kimi, opencodego, grok, or copilot");
|
|
6289
7045
|
}
|
|
6290
7046
|
const accountId = rest.length >= 2 ? rest[1] : params.get("accountId") ?? void 0;
|
|
6291
7047
|
const allowances = await service.list({ providerId, accountId });
|
|
@@ -6327,6 +7083,26 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
|
|
|
6327
7083
|
}
|
|
6328
7084
|
return writeJson3(res, 200, { allowances: allowances2 });
|
|
6329
7085
|
}
|
|
7086
|
+
if (requestedProvider === "copilot") {
|
|
7087
|
+
if (!service.refreshCopilot) {
|
|
7088
|
+
return writeError2(res, 501, "copilot allowance refresh is not available");
|
|
7089
|
+
}
|
|
7090
|
+
const allowances2 = await service.refreshCopilot(accountId);
|
|
7091
|
+
if (accountId && allowances2.length === 0) {
|
|
7092
|
+
return writeError2(res, 404, `Copilot account '${accountId}' not found`);
|
|
7093
|
+
}
|
|
7094
|
+
return writeJson3(res, 200, { allowances: allowances2 });
|
|
7095
|
+
}
|
|
7096
|
+
if (requestedProvider === "grok") {
|
|
7097
|
+
if (!service.refreshGrok) {
|
|
7098
|
+
return writeError2(res, 501, "grok allowance refresh is not available");
|
|
7099
|
+
}
|
|
7100
|
+
const allowances2 = await service.refreshGrok(accountId);
|
|
7101
|
+
if (accountId && allowances2.length === 0) {
|
|
7102
|
+
return writeError2(res, 404, `Grok account '${accountId}' not found`);
|
|
7103
|
+
}
|
|
7104
|
+
return writeJson3(res, 200, { allowances: allowances2 });
|
|
7105
|
+
}
|
|
6330
7106
|
const allowances = await service.refreshClaude(accountId);
|
|
6331
7107
|
if (accountId && allowances.length === 0) {
|
|
6332
7108
|
return writeError2(res, 404, `Claude account '${accountId}' not found`);
|
|
@@ -6428,6 +7204,9 @@ function toProviderView(row) {
|
|
|
6428
7204
|
apiVersion: row.apiVersion,
|
|
6429
7205
|
maxConcurrency: row.maxConcurrency,
|
|
6430
7206
|
modelsEndpoint: row.modelsEndpoint,
|
|
7207
|
+
// Static extra headers round-trip VERBATIM (non-secret identity values;
|
|
7208
|
+
// auth/content names were already dropped at the write/load gate).
|
|
7209
|
+
extraHeaders: row.extraHeaders,
|
|
6431
7210
|
// app-parity child 5: transformer config round-trips VERBATIM (non-secret —
|
|
6432
7211
|
// transform-rule names + options, no key material; absent stays absent).
|
|
6433
7212
|
transformer: row.transformer,
|
|
@@ -6497,8 +7276,8 @@ async function handleAdminApi(req, res, path2, deps) {
|
|
|
6497
7276
|
default:
|
|
6498
7277
|
return writeJsonError(res, 404, `unknown admin resource '${resource}'`);
|
|
6499
7278
|
}
|
|
6500
|
-
} catch (
|
|
6501
|
-
writeJsonError(res, 500,
|
|
7279
|
+
} catch (err8) {
|
|
7280
|
+
writeJsonError(res, 500, err8 instanceof Error ? err8.message : String(err8));
|
|
6502
7281
|
}
|
|
6503
7282
|
}
|
|
6504
7283
|
function requestQuery(req) {
|
|
@@ -6656,6 +7435,9 @@ async function handleProviderReorder(req, res, cfg, deps) {
|
|
|
6656
7435
|
persistProviders(cfg, deps);
|
|
6657
7436
|
return writeJson4(res, 200, { ok: true, providers: cfg.providers.map(toProviderView) });
|
|
6658
7437
|
}
|
|
7438
|
+
function expandRowExtraHeaders(row) {
|
|
7439
|
+
return mergeExtraHeaders({}, row.extraHeaders);
|
|
7440
|
+
}
|
|
6659
7441
|
async function handleDiscoverModels(res, id, cfg) {
|
|
6660
7442
|
if (!id) return writeJsonError(res, 400, "provider id required in path");
|
|
6661
7443
|
const row = cfg.providers.find((p) => p.id === id);
|
|
@@ -6669,7 +7451,8 @@ async function handleDiscoverModels(res, id, cfg) {
|
|
|
6669
7451
|
try {
|
|
6670
7452
|
const headers = { Accept: "application/json" };
|
|
6671
7453
|
if (resolvedKey) headers["Authorization"] = `Bearer ${resolvedKey}`;
|
|
6672
|
-
|
|
7454
|
+
Object.assign(headers, expandRowExtraHeaders(row));
|
|
7455
|
+
const response = await fetchUpstream7(url, { method: "GET", headers }, { providerId: "byo" });
|
|
6673
7456
|
if (!response.ok) {
|
|
6674
7457
|
const text = await response.text().catch(() => "");
|
|
6675
7458
|
let message = text.slice(0, 300);
|
|
@@ -6686,8 +7469,8 @@ async function handleDiscoverModels(res, id, cfg) {
|
|
|
6686
7469
|
const data = await response.json();
|
|
6687
7470
|
const models = Array.isArray(data?.data) ? data.data.map((m) => typeof m?.id === "string" ? m.id : "").filter((m) => m.length > 0) : [];
|
|
6688
7471
|
return writeJson4(res, 200, { models });
|
|
6689
|
-
} catch (
|
|
6690
|
-
const message =
|
|
7472
|
+
} catch (err8) {
|
|
7473
|
+
const message = err8 instanceof Error ? err8.message : String(err8);
|
|
6691
7474
|
return writeJson4(res, 200, { models: [], error: `discovery failed: ${message}` });
|
|
6692
7475
|
}
|
|
6693
7476
|
}
|
|
@@ -6726,9 +7509,10 @@ async function handleTestModel(req, res, id, cfg) {
|
|
|
6726
7509
|
messages: [{ role: "user", content: prompt }]
|
|
6727
7510
|
};
|
|
6728
7511
|
}
|
|
7512
|
+
Object.assign(headers, expandRowExtraHeaders(row));
|
|
6729
7513
|
const startedAt = Date.now();
|
|
6730
7514
|
try {
|
|
6731
|
-
const response = await
|
|
7515
|
+
const response = await fetchUpstream7(
|
|
6732
7516
|
url,
|
|
6733
7517
|
{ method: "POST", headers, body: JSON.stringify(payload) },
|
|
6734
7518
|
{ providerId: "byo" }
|
|
@@ -6750,8 +7534,8 @@ async function handleTestModel(req, res, id, cfg) {
|
|
|
6750
7534
|
latencyMs,
|
|
6751
7535
|
sample: extractSampleText(text, row.apiFormat)
|
|
6752
7536
|
});
|
|
6753
|
-
} catch (
|
|
6754
|
-
const message =
|
|
7537
|
+
} catch (err8) {
|
|
7538
|
+
const message = err8 instanceof Error ? err8.message : String(err8);
|
|
6755
7539
|
return writeJson4(res, 200, { ok: false, latencyMs: Date.now() - startedAt, message });
|
|
6756
7540
|
}
|
|
6757
7541
|
}
|
|
@@ -7033,6 +7817,7 @@ function parseProviderInput(body, existing) {
|
|
|
7033
7817
|
const apiVersion = typeof body["apiVersion"] === "string" && body["apiVersion"].length > 0 ? body["apiVersion"] : body["apiVersion"] === null ? void 0 : existing?.apiVersion;
|
|
7034
7818
|
const modelsEndpoint = typeof body["modelsEndpoint"] === "string" && body["modelsEndpoint"].length > 0 ? body["modelsEndpoint"] : body["modelsEndpoint"] === null ? void 0 : existing?.modelsEndpoint;
|
|
7035
7819
|
const maxConcurrency = typeof body["maxConcurrency"] === "number" && Number.isFinite(body["maxConcurrency"]) ? body["maxConcurrency"] : body["maxConcurrency"] === null ? void 0 : existing?.maxConcurrency;
|
|
7820
|
+
const extraHeaders = body["extraHeaders"] === null ? void 0 : body["extraHeaders"] === void 0 ? existing?.extraHeaders : validateExtraHeaders(body["extraHeaders"]);
|
|
7036
7821
|
const transformer = body["transformer"] === null ? void 0 : parseTransformerInput(body["transformer"], existing?.transformer);
|
|
7037
7822
|
const codingPlan = body["codingPlan"] === null ? void 0 : body["codingPlan"] === void 0 ? existing?.codingPlan : body["codingPlan"] && typeof body["codingPlan"] === "object" && !Array.isArray(body["codingPlan"]) ? parseCodingPlanInput(body["codingPlan"], existing?.codingPlan) : existing?.codingPlan;
|
|
7038
7823
|
const apiModes = body["apiModes"] === null ? void 0 : parseApiModesInput(body["apiModes"], existing?.apiModes);
|
|
@@ -7058,6 +7843,7 @@ function parseProviderInput(body, existing) {
|
|
|
7058
7843
|
apiVersion,
|
|
7059
7844
|
maxConcurrency,
|
|
7060
7845
|
modelsEndpoint,
|
|
7846
|
+
extraHeaders,
|
|
7061
7847
|
transformer: migrated.transformer,
|
|
7062
7848
|
codingPlan,
|
|
7063
7849
|
apiModes,
|
|
@@ -7079,7 +7865,10 @@ function handlePresets(res, method) {
|
|
|
7079
7865
|
description: p.description,
|
|
7080
7866
|
features: p.features,
|
|
7081
7867
|
website: p.website,
|
|
7082
|
-
modelsEndpoint: p.modelsEndpoint
|
|
7868
|
+
modelsEndpoint: p.modelsEndpoint,
|
|
7869
|
+
// Static extra headers ride along so `addFromPreset` can seed them onto the
|
|
7870
|
+
// row (the write gateway re-validates via the shared allowlist).
|
|
7871
|
+
extraHeaders: p.extraHeaders
|
|
7083
7872
|
}));
|
|
7084
7873
|
return writeJson4(res, 200, { presets, excluded });
|
|
7085
7874
|
}
|
|
@@ -7561,12 +8350,12 @@ async function handleAccounts(req, res, method, rest, deps) {
|
|
|
7561
8350
|
}
|
|
7562
8351
|
return writeJson4(res, 200, { ok: true, affected: result.affected });
|
|
7563
8352
|
}
|
|
7564
|
-
if (method === "GET" && (rest[0] === "codex" || rest[0] === "kimi") && rest[1] === "oauth" && rest[3] === "status") {
|
|
7565
|
-
const result = rest[0] === "codex" ? handleCodexOAuthStatus(rest[2], deps) : handleKimiOAuthStatus(rest[2], deps);
|
|
8353
|
+
if (method === "GET" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot") && rest[1] === "oauth" && rest[3] === "status") {
|
|
8354
|
+
const result = rest[0] === "codex" ? handleCodexOAuthStatus(rest[2], deps) : rest[0] === "kimi" ? handleKimiOAuthStatus(rest[2], deps) : rest[0] === "grok" ? handleGrokOAuthStatus(rest[2], deps) : handleCopilotOAuthStatus(rest[2], deps);
|
|
7566
8355
|
return writeJson4(res, result.status, result.body);
|
|
7567
8356
|
}
|
|
7568
|
-
if (method === "DELETE" && (rest[0] === "codex" || rest[0] === "kimi") && rest[1] === "oauth" && rest[2]) {
|
|
7569
|
-
const result = rest[0] === "codex" ? handleCodexOAuthCancel(rest[2], deps) : handleKimiOAuthCancel(rest[2], deps);
|
|
8357
|
+
if (method === "DELETE" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot") && rest[1] === "oauth" && rest[2]) {
|
|
8358
|
+
const result = rest[0] === "codex" ? handleCodexOAuthCancel(rest[2], deps) : rest[0] === "kimi" ? handleKimiOAuthCancel(rest[2], deps) : rest[0] === "grok" ? handleGrokOAuthCancel(rest[2], deps) : handleCopilotOAuthCancel(rest[2], deps);
|
|
7570
8359
|
return writeJson4(res, result.status, result.body);
|
|
7571
8360
|
}
|
|
7572
8361
|
if (method === "GET" && rest.length === 3 && rest[2] === "diagnostics") {
|
|
@@ -7627,6 +8416,15 @@ async function handleAccounts(req, res, method, rest, deps) {
|
|
|
7627
8416
|
const result2 = await handleKimiOAuthStart(deps);
|
|
7628
8417
|
return writeJson4(res, result2.status, result2.body);
|
|
7629
8418
|
}
|
|
8419
|
+
if (providerId === "grok") {
|
|
8420
|
+
const result2 = await handleGrokOAuthStart(deps);
|
|
8421
|
+
return writeJson4(res, result2.status, result2.body);
|
|
8422
|
+
}
|
|
8423
|
+
if (providerId === "copilot") {
|
|
8424
|
+
const body2 = await readJsonBody4(req);
|
|
8425
|
+
const result2 = await handleCopilotOAuthStart(deps, body2["enterpriseUrl"]);
|
|
8426
|
+
return writeJson4(res, result2.status, result2.body);
|
|
8427
|
+
}
|
|
7630
8428
|
const result = handleOAuthStart(providerId, deps);
|
|
7631
8429
|
return writeJson4(res, result.status, result.body);
|
|
7632
8430
|
}
|
|
@@ -8121,12 +8919,12 @@ async function handlePlayground(req, res, method, deps) {
|
|
|
8121
8919
|
const payload = body["body"];
|
|
8122
8920
|
const status = deps.outboundApiServer.getStatus();
|
|
8123
8921
|
if (!status.running || !status.port) return writeJsonError(res, 503, "outbound server not running");
|
|
8124
|
-
const path2 = resolvePlaygroundPath(endpoint,
|
|
8922
|
+
const path2 = resolvePlaygroundPath(endpoint, isRecord6(payload) ? payload : {});
|
|
8125
8923
|
if (!path2) return writeJsonError(res, 400, `unknown endpoint '${endpoint}'`);
|
|
8126
8924
|
const upstreamBody = typeof payload === "string" ? payload : JSON.stringify(payload ?? {});
|
|
8127
8925
|
await proxyToOutbound(res, status.port, path2, key, upstreamBody);
|
|
8128
8926
|
}
|
|
8129
|
-
function
|
|
8927
|
+
function isRecord6(v) {
|
|
8130
8928
|
return !!v && typeof v === "object" && !Array.isArray(v);
|
|
8131
8929
|
}
|
|
8132
8930
|
function proxyToOutbound(res, outboundPort, path2, key, body) {
|
|
@@ -8155,8 +8953,8 @@ function proxyToOutbound(res, outboundPort, path2, key, body) {
|
|
|
8155
8953
|
});
|
|
8156
8954
|
}
|
|
8157
8955
|
);
|
|
8158
|
-
upstream.on("error", (
|
|
8159
|
-
if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${
|
|
8956
|
+
upstream.on("error", (err8) => {
|
|
8957
|
+
if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${err8.message}`);
|
|
8160
8958
|
else res.end();
|
|
8161
8959
|
resolve10();
|
|
8162
8960
|
});
|
|
@@ -8261,7 +9059,7 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
|
|
|
8261
9059
|
}
|
|
8262
9060
|
|
|
8263
9061
|
// src/admin/version.ts
|
|
8264
|
-
var DAEMON_VERSION = true ? "0.
|
|
9062
|
+
var DAEMON_VERSION = true ? "0.4.0" : "0.0.0-dev";
|
|
8265
9063
|
|
|
8266
9064
|
// src/admin/AdminServer.ts
|
|
8267
9065
|
var LOOPBACK_ADDR = "127.0.0.1";
|
|
@@ -8304,13 +9102,13 @@ var AdminServer = class {
|
|
|
8304
9102
|
const server = http2.createServer((req, res) => {
|
|
8305
9103
|
this.onRequest(req, res);
|
|
8306
9104
|
});
|
|
8307
|
-
const onError = (
|
|
8308
|
-
if (
|
|
9105
|
+
const onError = (err8) => {
|
|
9106
|
+
if (err8.code === "EADDRINUSE" && port !== 0) {
|
|
8309
9107
|
server.removeListener("error", onError);
|
|
8310
9108
|
this.listen(bindAddr, 0).then(resolve10, reject);
|
|
8311
9109
|
return;
|
|
8312
9110
|
}
|
|
8313
|
-
reject(
|
|
9111
|
+
reject(err8);
|
|
8314
9112
|
};
|
|
8315
9113
|
server.on("error", onError);
|
|
8316
9114
|
server.listen(port, bindAddr, () => {
|
|
@@ -8328,8 +9126,8 @@ var AdminServer = class {
|
|
|
8328
9126
|
}
|
|
8329
9127
|
/** Per-request handler: auth gate (when a token is set) → routing. */
|
|
8330
9128
|
onRequest(req, res) {
|
|
8331
|
-
void this.dispatch(req, res).catch((
|
|
8332
|
-
const message =
|
|
9129
|
+
void this.dispatch(req, res).catch((err8) => {
|
|
9130
|
+
const message = err8 instanceof Error ? err8.message : String(err8);
|
|
8333
9131
|
this.deps.logger.error("[AdminServer] unhandled error:", message);
|
|
8334
9132
|
if (!res.headersSent) {
|
|
8335
9133
|
res.writeHead(500, { "Content-Type": "application/json" });
|
|
@@ -8593,18 +9391,18 @@ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal
|
|
|
8593
9391
|
return;
|
|
8594
9392
|
}
|
|
8595
9393
|
signal?.addEventListener("abort", abort, { once: true });
|
|
8596
|
-
server.on("error", (
|
|
9394
|
+
server.on("error", (err8) => {
|
|
8597
9395
|
if (settled) return;
|
|
8598
9396
|
settled = true;
|
|
8599
9397
|
clearTimeout(timer);
|
|
8600
|
-
if (
|
|
9398
|
+
if (err8.code === "EADDRINUSE") {
|
|
8601
9399
|
reject(
|
|
8602
9400
|
new Error(
|
|
8603
9401
|
`login: cannot bind ${LOOPBACK_HOST}:${LOOPBACK_PORT} (address in use) \u2014 another codex login or process is holding the port`
|
|
8604
9402
|
)
|
|
8605
9403
|
);
|
|
8606
9404
|
} else {
|
|
8607
|
-
reject(
|
|
9405
|
+
reject(err8);
|
|
8608
9406
|
}
|
|
8609
9407
|
});
|
|
8610
9408
|
const timer = setTimeout(() => {
|
|
@@ -8680,21 +9478,22 @@ function createPoolKeysLoader(getProviderRow, autoDisabled) {
|
|
|
8680
9478
|
}
|
|
8681
9479
|
|
|
8682
9480
|
// src/allowance/ProviderKeyQuotaService.ts
|
|
8683
|
-
import {
|
|
9481
|
+
import { mergeExtraHeaders as mergeExtraHeaders2 } from "@omnicross/core";
|
|
9482
|
+
import { fetchUpstream as fetchUpstream8 } from "@omnicross/core/pipeline/upstreamFetch";
|
|
8684
9483
|
|
|
8685
9484
|
// src/allowance/ProviderKeyQuota.ts
|
|
8686
|
-
var
|
|
8687
|
-
var HOUR_MS2 = 60 *
|
|
8688
|
-
var
|
|
8689
|
-
var WEEK_MS = 7 *
|
|
8690
|
-
var MONTH_MS = 30 *
|
|
8691
|
-
function
|
|
9485
|
+
var MINUTE_MS3 = 6e4;
|
|
9486
|
+
var HOUR_MS2 = 60 * MINUTE_MS3;
|
|
9487
|
+
var DAY_MS3 = 24 * HOUR_MS2;
|
|
9488
|
+
var WEEK_MS = 7 * DAY_MS3;
|
|
9489
|
+
var MONTH_MS = 30 * DAY_MS3;
|
|
9490
|
+
function finiteNumber5(value) {
|
|
8692
9491
|
if (value === null || value === void 0 || value === "") return void 0;
|
|
8693
9492
|
const parsed = typeof value === "number" ? value : Number(value);
|
|
8694
9493
|
return Number.isFinite(parsed) && parsed >= 0 ? parsed : void 0;
|
|
8695
9494
|
}
|
|
8696
9495
|
function finitePercent4(value) {
|
|
8697
|
-
const parsed =
|
|
9496
|
+
const parsed = finiteNumber5(value);
|
|
8698
9497
|
return parsed !== void 0 && parsed <= 100 ? parsed : null;
|
|
8699
9498
|
}
|
|
8700
9499
|
function isoInstant3(value) {
|
|
@@ -8702,18 +9501,18 @@ function isoInstant3(value) {
|
|
|
8702
9501
|
const time = Date.parse(value);
|
|
8703
9502
|
if (Number.isFinite(time)) return new Date(time).toISOString();
|
|
8704
9503
|
}
|
|
8705
|
-
const numeric =
|
|
9504
|
+
const numeric = finiteNumber5(value);
|
|
8706
9505
|
if (numeric !== void 0 && numeric > 1e9) {
|
|
8707
9506
|
const ms = numeric > 1e12 ? numeric : numeric * 1e3;
|
|
8708
9507
|
return new Date(ms).toISOString();
|
|
8709
9508
|
}
|
|
8710
9509
|
return void 0;
|
|
8711
9510
|
}
|
|
8712
|
-
function
|
|
9511
|
+
function secondsUntil7(instant, now) {
|
|
8713
9512
|
if (!instant) return void 0;
|
|
8714
9513
|
return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
|
|
8715
9514
|
}
|
|
8716
|
-
function
|
|
9515
|
+
function isRecord7(value) {
|
|
8717
9516
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
8718
9517
|
}
|
|
8719
9518
|
function detectProviderKeyQuotaAdapter(baseUrl) {
|
|
@@ -8736,6 +9535,7 @@ function detectProviderKeyQuotaAdapter(baseUrl) {
|
|
|
8736
9535
|
}
|
|
8737
9536
|
if (host === "api.code.umans.ai") return "umans";
|
|
8738
9537
|
if (host === "api.synthetic.new") return "synthetic";
|
|
9538
|
+
if (host === "api.cline.bot") return "cline-pass";
|
|
8739
9539
|
return null;
|
|
8740
9540
|
}
|
|
8741
9541
|
function providerKeyQuotaUrl(adapter, baseUrl) {
|
|
@@ -8743,6 +9543,7 @@ function providerKeyQuotaUrl(adapter, baseUrl) {
|
|
|
8743
9543
|
if (adapter === "zai") return `${origin}/api/monitor/usage/quota/limit`;
|
|
8744
9544
|
if (adapter === "minimax-token-plan") return `${origin}/v1/token_plan/remains`;
|
|
8745
9545
|
if (adapter === "umans") return `${origin}/v1/usage`;
|
|
9546
|
+
if (adapter === "cline-pass") return `${origin}/api/v1/users/me/plan/usage-limits`;
|
|
8746
9547
|
return `${origin}/v2/quotas`;
|
|
8747
9548
|
}
|
|
8748
9549
|
function providerKeyQuotaAuthHeader(adapter, key) {
|
|
@@ -8754,7 +9555,7 @@ function zaiWindowDurationMs(item) {
|
|
|
8754
9555
|
case 3:
|
|
8755
9556
|
return count * HOUR_MS2;
|
|
8756
9557
|
case 4:
|
|
8757
|
-
return count *
|
|
9558
|
+
return count * DAY_MS3;
|
|
8758
9559
|
case 5:
|
|
8759
9560
|
return count * MONTH_MS;
|
|
8760
9561
|
case 6:
|
|
@@ -8767,8 +9568,8 @@ function zaiWindowIdLabel(durationMs) {
|
|
|
8767
9568
|
if (durationMs === WEEK_MS) return { id: "seven-day", label: "7 days" };
|
|
8768
9569
|
if (durationMs === 5 * HOUR_MS2) return { id: "five-hour", label: "5 hours" };
|
|
8769
9570
|
if (durationMs === MONTH_MS) return { id: "thirty-day", label: "30 days" };
|
|
8770
|
-
if (durationMs !== void 0 && durationMs %
|
|
8771
|
-
const days = durationMs /
|
|
9571
|
+
if (durationMs !== void 0 && durationMs % DAY_MS3 === 0) {
|
|
9572
|
+
const days = durationMs / DAY_MS3;
|
|
8772
9573
|
return { id: `${days}d`, label: `${days} day${days === 1 ? "" : "s"}` };
|
|
8773
9574
|
}
|
|
8774
9575
|
if (durationMs !== void 0 && durationMs % HOUR_MS2 === 0) {
|
|
@@ -8778,23 +9579,23 @@ function zaiWindowIdLabel(durationMs) {
|
|
|
8778
9579
|
return { id: "quota", label: "Quota" };
|
|
8779
9580
|
}
|
|
8780
9581
|
function parseZaiQuotaPayload(payload, now) {
|
|
8781
|
-
if (!
|
|
8782
|
-
const data =
|
|
9582
|
+
if (!isRecord7(payload)) return null;
|
|
9583
|
+
const data = isRecord7(payload["data"]) ? payload["data"] : payload;
|
|
8783
9584
|
if (payload["success"] === false) return null;
|
|
8784
9585
|
const limits = Array.isArray(data["limits"]) ? data["limits"] : [];
|
|
8785
9586
|
const byWindow = /* @__PURE__ */ new Map();
|
|
8786
9587
|
for (const raw of limits) {
|
|
8787
|
-
if (!
|
|
9588
|
+
if (!isRecord7(raw)) continue;
|
|
8788
9589
|
const item = raw;
|
|
8789
9590
|
if (item.type === void 0) continue;
|
|
8790
9591
|
const details = raw["usageDetails"];
|
|
8791
|
-
if (Array.isArray(details) && details.some((d) =>
|
|
9592
|
+
if (Array.isArray(details) && details.some((d) => isRecord7(d) && d["modelCode"] === "zread")) {
|
|
8792
9593
|
continue;
|
|
8793
9594
|
}
|
|
8794
9595
|
const durationMs = zaiWindowDurationMs(item);
|
|
8795
9596
|
const { id, label } = zaiWindowIdLabel(durationMs);
|
|
8796
|
-
const limit =
|
|
8797
|
-
const used =
|
|
9597
|
+
const limit = finiteNumber5(item.usage);
|
|
9598
|
+
const used = finiteNumber5(item.currentValue);
|
|
8798
9599
|
const fromAbsolute = limit !== void 0 && used !== void 0 && limit > 0 ? Math.min(100, used / limit * 100) : void 0;
|
|
8799
9600
|
const fromPercentage = finitePercent4(item.percentage) ?? void 0;
|
|
8800
9601
|
const usedPercent = fromAbsolute !== void 0 ? Math.round(fromAbsolute * 10) / 10 : fromPercentage;
|
|
@@ -8805,9 +9606,9 @@ function parseZaiQuotaPayload(payload, now) {
|
|
|
8805
9606
|
label,
|
|
8806
9607
|
scope: "all",
|
|
8807
9608
|
usedPercent,
|
|
8808
|
-
...durationMs !== void 0 ? { windowMinutes: Math.round(durationMs /
|
|
9609
|
+
...durationMs !== void 0 ? { windowMinutes: Math.round(durationMs / MINUTE_MS3) } : {},
|
|
8809
9610
|
...resetsAt !== void 0 ? { resetsAt } : {},
|
|
8810
|
-
remainingSeconds:
|
|
9611
|
+
remainingSeconds: secondsUntil7(resetsAt, now),
|
|
8811
9612
|
state: "fresh"
|
|
8812
9613
|
};
|
|
8813
9614
|
const existing = byWindow.get(id);
|
|
@@ -8821,21 +9622,21 @@ function parseZaiQuotaPayload(payload, now) {
|
|
|
8821
9622
|
var MINIMAX_STATUS_EXHAUSTED = 2;
|
|
8822
9623
|
var MINIMAX_SHARED_BUCKET = "general";
|
|
8823
9624
|
function parseMiniMaxBucket(value) {
|
|
8824
|
-
if (!
|
|
9625
|
+
if (!isRecord7(value)) return null;
|
|
8825
9626
|
const modelName = typeof value["model_name"] === "string" ? value["model_name"].trim() : "";
|
|
8826
9627
|
if (!modelName) return null;
|
|
8827
9628
|
const instant = (v) => {
|
|
8828
|
-
const n =
|
|
9629
|
+
const n = finiteNumber5(v);
|
|
8829
9630
|
return n !== void 0 && n > 1e9 ? n > 1e12 ? n : n * 1e3 : void 0;
|
|
8830
9631
|
};
|
|
8831
9632
|
return {
|
|
8832
9633
|
modelName,
|
|
8833
9634
|
intervalEnd: instant(value["end_time"]),
|
|
8834
|
-
intervalRemainingPercent:
|
|
8835
|
-
intervalStatus:
|
|
9635
|
+
intervalRemainingPercent: finiteNumber5(value["current_interval_remaining_percent"]),
|
|
9636
|
+
intervalStatus: finiteNumber5(value["current_interval_status"]),
|
|
8836
9637
|
weeklyEnd: instant(value["weekly_end_time"]),
|
|
8837
|
-
weeklyRemainingPercent:
|
|
8838
|
-
weeklyStatus:
|
|
9638
|
+
weeklyRemainingPercent: finiteNumber5(value["current_weekly_remaining_percent"]),
|
|
9639
|
+
weeklyStatus: finiteNumber5(value["current_weekly_status"])
|
|
8839
9640
|
};
|
|
8840
9641
|
}
|
|
8841
9642
|
function minimaxWindow(id, label, windowMinutes, resetsAtMs, remainingPercent, status, now) {
|
|
@@ -8848,14 +9649,14 @@ function minimaxWindow(id, label, windowMinutes, resetsAtMs, remainingPercent, s
|
|
|
8848
9649
|
usedPercent,
|
|
8849
9650
|
...windowMinutes !== void 0 ? { windowMinutes } : {},
|
|
8850
9651
|
...resetsAt !== void 0 ? { resetsAt } : {},
|
|
8851
|
-
remainingSeconds:
|
|
9652
|
+
remainingSeconds: secondsUntil7(resetsAt, now),
|
|
8852
9653
|
state: usedPercent !== null ? "fresh" : "unavailable"
|
|
8853
9654
|
};
|
|
8854
9655
|
}
|
|
8855
9656
|
function parseMiniMaxTokenPlanPayload(payload, now) {
|
|
8856
|
-
if (!
|
|
9657
|
+
if (!isRecord7(payload)) return null;
|
|
8857
9658
|
const baseResp = payload["base_resp"];
|
|
8858
|
-
if (!
|
|
9659
|
+
if (!isRecord7(baseResp) || baseResp["status_code"] !== 0) return null;
|
|
8859
9660
|
const buckets = Array.isArray(payload["model_remains"]) ? payload["model_remains"] : [];
|
|
8860
9661
|
let general = null;
|
|
8861
9662
|
for (const raw of buckets) {
|
|
@@ -8879,7 +9680,7 @@ function parseMiniMaxTokenPlanPayload(payload, now) {
|
|
|
8879
9680
|
minimaxWindow(
|
|
8880
9681
|
"seven-day",
|
|
8881
9682
|
"7 days",
|
|
8882
|
-
Math.round(WEEK_MS /
|
|
9683
|
+
Math.round(WEEK_MS / MINUTE_MS3),
|
|
8883
9684
|
general.weeklyEnd,
|
|
8884
9685
|
general.weeklyRemainingPercent,
|
|
8885
9686
|
general.weeklyStatus,
|
|
@@ -8888,15 +9689,15 @@ function parseMiniMaxTokenPlanPayload(payload, now) {
|
|
|
8888
9689
|
];
|
|
8889
9690
|
}
|
|
8890
9691
|
function parseUmansUsagePayload(payload, now) {
|
|
8891
|
-
if (!
|
|
8892
|
-
const limits =
|
|
8893
|
-
const requests = limits &&
|
|
8894
|
-
const usage =
|
|
8895
|
-
const window =
|
|
8896
|
-
const hardCap =
|
|
8897
|
-
const softLimit =
|
|
8898
|
-
const requestsInWindow =
|
|
8899
|
-
const weightedInWindow =
|
|
9692
|
+
if (!isRecord7(payload)) return null;
|
|
9693
|
+
const limits = isRecord7(payload["limits"]) ? payload["limits"] : void 0;
|
|
9694
|
+
const requests = limits && isRecord7(limits["requests"]) ? limits["requests"] : void 0;
|
|
9695
|
+
const usage = isRecord7(payload["usage"]) ? payload["usage"] : void 0;
|
|
9696
|
+
const window = isRecord7(payload["window"]) ? payload["window"] : void 0;
|
|
9697
|
+
const hardCap = finiteNumber5(requests?.["hard_cap"]);
|
|
9698
|
+
const softLimit = finiteNumber5(requests?.["limit"]);
|
|
9699
|
+
const requestsInWindow = finiteNumber5(usage?.["requests_in_window"]);
|
|
9700
|
+
const weightedInWindow = finiteNumber5(usage?.["weighted_in_window"]);
|
|
8900
9701
|
const resetsAt = isoInstant3(window?.["resets_at"]);
|
|
8901
9702
|
let usedPercent = null;
|
|
8902
9703
|
if (hardCap !== void 0 && hardCap > 0 && requestsInWindow !== void 0) {
|
|
@@ -8913,19 +9714,19 @@ function parseUmansUsagePayload(payload, now) {
|
|
|
8913
9714
|
usedPercent,
|
|
8914
9715
|
windowMinutes: 5 * 60,
|
|
8915
9716
|
...resetsAt !== void 0 ? { resetsAt } : {},
|
|
8916
|
-
remainingSeconds:
|
|
9717
|
+
remainingSeconds: secondsUntil7(resetsAt, now),
|
|
8917
9718
|
state: "fresh"
|
|
8918
9719
|
}
|
|
8919
9720
|
];
|
|
8920
9721
|
}
|
|
8921
9722
|
function parseSyntheticQuotasPayload(payload, now) {
|
|
8922
|
-
if (!
|
|
8923
|
-
const fiveHour =
|
|
8924
|
-
const weekly =
|
|
9723
|
+
if (!isRecord7(payload)) return null;
|
|
9724
|
+
const fiveHour = isRecord7(payload["rollingFiveHourLimit"]) ? payload["rollingFiveHourLimit"] : void 0;
|
|
9725
|
+
const weekly = isRecord7(payload["weeklyTokenLimit"]) ? payload["weeklyTokenLimit"] : void 0;
|
|
8925
9726
|
const windows = [];
|
|
8926
9727
|
if (fiveHour) {
|
|
8927
|
-
const max =
|
|
8928
|
-
const remaining =
|
|
9728
|
+
const max = finiteNumber5(fiveHour["max"]);
|
|
9729
|
+
const remaining = finiteNumber5(fiveHour["remaining"]);
|
|
8929
9730
|
const usedPercent = max !== void 0 && max > 0 && remaining !== void 0 ? Math.round(Math.min(100, (max - remaining) / max * 100) * 10) / 10 : null;
|
|
8930
9731
|
const resetsAt = isoInstant3(fiveHour["nextTickAt"]);
|
|
8931
9732
|
windows.push({
|
|
@@ -8935,12 +9736,12 @@ function parseSyntheticQuotasPayload(payload, now) {
|
|
|
8935
9736
|
usedPercent,
|
|
8936
9737
|
windowMinutes: 5 * 60,
|
|
8937
9738
|
...resetsAt !== void 0 ? { resetsAt } : {},
|
|
8938
|
-
remainingSeconds:
|
|
9739
|
+
remainingSeconds: secondsUntil7(resetsAt, now),
|
|
8939
9740
|
state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
|
|
8940
9741
|
});
|
|
8941
9742
|
}
|
|
8942
9743
|
if (weekly) {
|
|
8943
|
-
const percentRemaining =
|
|
9744
|
+
const percentRemaining = finiteNumber5(weekly["percentRemaining"]);
|
|
8944
9745
|
const usedPercent = percentRemaining !== void 0 ? Math.round(Math.min(100, Math.max(0, 100 - percentRemaining)) * 10) / 10 : null;
|
|
8945
9746
|
const resetsAt = isoInstant3(weekly["nextRegenAt"]);
|
|
8946
9747
|
windows.push({
|
|
@@ -8950,12 +9751,42 @@ function parseSyntheticQuotasPayload(payload, now) {
|
|
|
8950
9751
|
usedPercent,
|
|
8951
9752
|
windowMinutes: 7 * 24 * 60,
|
|
8952
9753
|
...resetsAt !== void 0 ? { resetsAt } : {},
|
|
8953
|
-
remainingSeconds:
|
|
9754
|
+
remainingSeconds: secondsUntil7(resetsAt, now),
|
|
8954
9755
|
state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
|
|
8955
9756
|
});
|
|
8956
9757
|
}
|
|
8957
9758
|
return windows.length > 0 ? windows : null;
|
|
8958
9759
|
}
|
|
9760
|
+
var CLINE_WINDOW_CONFIG = {
|
|
9761
|
+
five_hour: { id: "five-hour", label: "5 hours", minutes: 5 * 60 },
|
|
9762
|
+
weekly: { id: "seven-day", label: "7 days", minutes: 7 * 24 * 60 },
|
|
9763
|
+
monthly: { id: "thirty-day", label: "30 days", minutes: 30 * 24 * 60 }
|
|
9764
|
+
};
|
|
9765
|
+
function parseClinePassUsageLimitsPayload(payload, now) {
|
|
9766
|
+
if (!isRecord7(payload)) return null;
|
|
9767
|
+
const data = isRecord7(payload["data"]) ? payload["data"] : payload;
|
|
9768
|
+
const limits = Array.isArray(data["limits"]) ? data["limits"] : [];
|
|
9769
|
+
const windows = [];
|
|
9770
|
+
for (const raw of limits) {
|
|
9771
|
+
if (!isRecord7(raw)) continue;
|
|
9772
|
+
const config = CLINE_WINDOW_CONFIG[typeof raw["type"] === "string" ? raw["type"] : ""];
|
|
9773
|
+
if (!config) continue;
|
|
9774
|
+
const usedPercent = finitePercent4(raw["percentUsed"]);
|
|
9775
|
+
if (usedPercent === null) continue;
|
|
9776
|
+
const resetsAt = isoInstant3(raw["resetsAt"]);
|
|
9777
|
+
windows.push({
|
|
9778
|
+
id: config.id,
|
|
9779
|
+
label: config.label,
|
|
9780
|
+
scope: "all",
|
|
9781
|
+
usedPercent,
|
|
9782
|
+
windowMinutes: config.minutes,
|
|
9783
|
+
...resetsAt !== void 0 ? { resetsAt } : {},
|
|
9784
|
+
remainingSeconds: secondsUntil7(resetsAt, now),
|
|
9785
|
+
state: "fresh"
|
|
9786
|
+
});
|
|
9787
|
+
}
|
|
9788
|
+
return windows.length > 0 ? windows : null;
|
|
9789
|
+
}
|
|
8959
9790
|
|
|
8960
9791
|
// src/allowance/ProviderKeyQuotaService.ts
|
|
8961
9792
|
function parseQuotaPayload(adapter, payload, now) {
|
|
@@ -8968,6 +9799,8 @@ function parseQuotaPayload(adapter, payload, now) {
|
|
|
8968
9799
|
return parseUmansUsagePayload(payload, now);
|
|
8969
9800
|
case "synthetic":
|
|
8970
9801
|
return parseSyntheticQuotasPayload(payload, now);
|
|
9802
|
+
case "cline-pass":
|
|
9803
|
+
return parseClinePassUsageLimitsPayload(payload, now);
|
|
8971
9804
|
}
|
|
8972
9805
|
}
|
|
8973
9806
|
var PROVIDER_KEY_QUOTA_CACHE_MS = 5 * 6e4;
|
|
@@ -8987,7 +9820,7 @@ function rowKeyEntries(row) {
|
|
|
8987
9820
|
return [];
|
|
8988
9821
|
}
|
|
8989
9822
|
var ProviderKeyQuotaService = class {
|
|
8990
|
-
constructor(box, fetchImpl = (url, init) =>
|
|
9823
|
+
constructor(box, fetchImpl = (url, init) => fetchUpstream8(url, init, { redactBodies: true }), now = Date.now) {
|
|
8991
9824
|
this.box = box;
|
|
8992
9825
|
this.fetchImpl = fetchImpl;
|
|
8993
9826
|
this.now = now;
|
|
@@ -9049,7 +9882,10 @@ var ProviderKeyQuotaService = class {
|
|
|
9049
9882
|
headers: {
|
|
9050
9883
|
Authorization: providerKeyQuotaAuthHeader(adapter, key),
|
|
9051
9884
|
Accept: "application/json",
|
|
9052
|
-
"Content-Type": "application/json"
|
|
9885
|
+
"Content-Type": "application/json",
|
|
9886
|
+
// The row's static identity headers ride along — the Cline usage
|
|
9887
|
+
// endpoint sits behind the SAME client-identity 403 gate as inference.
|
|
9888
|
+
...mergeExtraHeaders2({}, row.extraHeaders)
|
|
9053
9889
|
},
|
|
9054
9890
|
signal: AbortSignal.timeout(15e3)
|
|
9055
9891
|
});
|
|
@@ -13854,6 +14690,10 @@ function toLLMProvider(row) {
|
|
|
13854
14690
|
// `parseProviderInput`), so customizations are preserved (the row value wins).
|
|
13855
14691
|
apiModes: row.apiModes,
|
|
13856
14692
|
selectedApiModeId: row.selectedApiModeId,
|
|
14693
|
+
// Static extra request headers ride along verbatim (load-guarded — no
|
|
14694
|
+
// auth/content names); core's `getProviderHeaders` merges them into every
|
|
14695
|
+
// BYO request, and the same-format relay path inherits that funnel.
|
|
14696
|
+
extraHeaders: row.extraHeaders,
|
|
13857
14697
|
// Official-Anthropic signature handling only matters for the Anthropic
|
|
13858
14698
|
// ingress (deferred → 502); leave it off for the BYO transform path.
|
|
13859
14699
|
isOfficial: false
|
|
@@ -15803,12 +16643,13 @@ import { existsSync as existsSync22, mkdirSync as mkdirSync6, readFileSync as re
|
|
|
15803
16643
|
import { dirname as dirname15 } from "path";
|
|
15804
16644
|
import { getSharedAccountHealth as getSharedAccountHealth2 } from "@omnicross/core/pipeline/SubscriptionAccountHealth";
|
|
15805
16645
|
import { getSharedAccountAllowanceScheduling as getSharedAccountAllowanceScheduling3 } from "@omnicross/core/pipeline/AccountAllowanceScheduling";
|
|
15806
|
-
import { fetchUpstream as
|
|
16646
|
+
import { fetchUpstream as fetchUpstream9 } from "@omnicross/core/pipeline/upstreamFetch";
|
|
15807
16647
|
import { getSharedIdentityStore as getSharedIdentityStore2 } from "@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore";
|
|
15808
16648
|
import {
|
|
15809
16649
|
claudeOAuth as claudeOAuth2,
|
|
15810
16650
|
codexOAuth as codexOAuth2,
|
|
15811
16651
|
geminiOAuth as geminiOAuth2,
|
|
16652
|
+
grokOAuth as grokOAuth2,
|
|
15812
16653
|
kimiOAuth as kimiOAuth2
|
|
15813
16654
|
} from "@omnicross/subscriptions";
|
|
15814
16655
|
|
|
@@ -15958,7 +16799,7 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
15958
16799
|
* a plaintext token pair into `upstream-trace.jsonl`.
|
|
15959
16800
|
*/
|
|
15960
16801
|
buildRefreshFetch(providerId, accountId) {
|
|
15961
|
-
return this.fetchImpl ?? ((url, init) =>
|
|
16802
|
+
return this.fetchImpl ?? ((url, init) => fetchUpstream9(url, init, { providerId, accountId, redactBodies: true }));
|
|
15962
16803
|
}
|
|
15963
16804
|
/**
|
|
15964
16805
|
* In-flight refresh coalescing. OAuth refresh tokens are
|
|
@@ -15999,7 +16840,7 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
15999
16840
|
* other hot reads. Never returns token material.
|
|
16000
16841
|
*/
|
|
16001
16842
|
getAccountProxy(providerId, accountId) {
|
|
16002
|
-
if (providerId !== "claude" && providerId !== "codex" && providerId !== "gemini" && providerId !== "opencodego" && providerId !== "kimi") {
|
|
16843
|
+
if (providerId !== "claude" && providerId !== "codex" && providerId !== "gemini" && providerId !== "opencodego" && providerId !== "kimi" && providerId !== "grok" && providerId !== "copilot") {
|
|
16003
16844
|
return void 0;
|
|
16004
16845
|
}
|
|
16005
16846
|
return getAccountProxy(this.readConfig(), providerId, accountId);
|
|
@@ -16018,7 +16859,7 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
16018
16859
|
const fingerprintOn = identityStore.isEnabled();
|
|
16019
16860
|
const now = Date.now();
|
|
16020
16861
|
const out = {};
|
|
16021
|
-
for (const provider of ["claude", "codex", "gemini", "opencodego", "kimi"]) {
|
|
16862
|
+
for (const provider of ["claude", "codex", "gemini", "opencodego", "kimi", "grok", "copilot"]) {
|
|
16022
16863
|
const sanitized = sanitizeAccounts(config, provider);
|
|
16023
16864
|
if (sanitized.length === 0) continue;
|
|
16024
16865
|
for (const account of sanitized) {
|
|
@@ -16217,6 +17058,66 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
16217
17058
|
}
|
|
16218
17059
|
});
|
|
16219
17060
|
}
|
|
17061
|
+
/**
|
|
17062
|
+
* Refresh the Grok (xAI SuperGrok) OAuth access token. The token endpoint is
|
|
17063
|
+
* resolved through OIDC discovery on every refresh (process-cached 1h by the
|
|
17064
|
+
* flow module) so a rotated endpoint document is picked up without a daemon
|
|
17065
|
+
* restart. HONEST `false` when no refresh_token.
|
|
17066
|
+
*/
|
|
17067
|
+
async refreshGrokToken() {
|
|
17068
|
+
return this.coalesce("grok:active", async () => {
|
|
17069
|
+
const config = this.readConfig();
|
|
17070
|
+
const active = getActiveAccount(config, "grok");
|
|
17071
|
+
const grok = active?.tokens;
|
|
17072
|
+
if (!active || !grok?.refreshToken) return false;
|
|
17073
|
+
const capturedId = active.id;
|
|
17074
|
+
this.materializeMigration(config);
|
|
17075
|
+
const refreshFetch = this.buildRefreshFetch("grok", capturedId);
|
|
17076
|
+
try {
|
|
17077
|
+
const tokenEndpoint = await grokOAuth2.resolveGrokTokenEndpoint(refreshFetch);
|
|
17078
|
+
const result = await grokOAuth2.refreshGrokAccessToken(grok.refreshToken, tokenEndpoint, refreshFetch);
|
|
17079
|
+
const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
|
|
17080
|
+
const next = {
|
|
17081
|
+
...grok,
|
|
17082
|
+
accessToken: result.accessToken,
|
|
17083
|
+
refreshToken: result.refreshToken,
|
|
17084
|
+
expiresAt,
|
|
17085
|
+
status: "authorized",
|
|
17086
|
+
lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
17087
|
+
errorMessage: void 0,
|
|
17088
|
+
syncWarning: void 0
|
|
17089
|
+
};
|
|
17090
|
+
this.writeBackById("grok", capturedId, next);
|
|
17091
|
+
return true;
|
|
17092
|
+
} catch (error) {
|
|
17093
|
+
this.markExpiredById("grok", capturedId, grok, error);
|
|
17094
|
+
return false;
|
|
17095
|
+
}
|
|
17096
|
+
});
|
|
17097
|
+
}
|
|
17098
|
+
/**
|
|
17099
|
+
* "Refresh" a GitHub Copilot token — there is nothing to refresh (ghu_
|
|
17100
|
+
* tokens are long-lived with no exchange endpoint). A call here means the
|
|
17101
|
+
* strategy saw a 401 (the token was revoked); mark the account `expired`
|
|
17102
|
+
* with a re-authenticate message and return `false` (the proxy then declines
|
|
17103
|
+
* the retry instead of looping on a dead token).
|
|
17104
|
+
*/
|
|
17105
|
+
async refreshCopilotToken() {
|
|
17106
|
+
return this.coalesce("copilot:active", async () => {
|
|
17107
|
+
const config = this.readConfig();
|
|
17108
|
+
const active = getActiveAccount(config, "copilot");
|
|
17109
|
+
const copilot = active?.tokens;
|
|
17110
|
+
if (!active || !copilot?.accessToken) return false;
|
|
17111
|
+
this.materializeMigration(config);
|
|
17112
|
+
this.markExpiredById(
|
|
17113
|
+
"copilot",
|
|
17114
|
+
active.id,
|
|
17115
|
+
copilot,
|
|
17116
|
+
new Error("GitHub Copilot tokens cannot be refreshed \u2014 re-authenticate the account")
|
|
17117
|
+
);
|
|
17118
|
+
return false;
|
|
17119
|
+
});
|
|
17120
|
+
}
|
|
16220
17121
|
/**
|
|
16221
17122
|
* Refresh a SPECIFIC managed account by id (background scheduler sweep and
|
|
16222
17123
|
* account-pool resolution). It uses only that account's stored refresh
|
|
@@ -16269,7 +17170,7 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
16269
17170
|
}
|
|
16270
17171
|
const oauth = account.tokens;
|
|
16271
17172
|
if (!oauth.accessToken) return null;
|
|
16272
|
-
if (providerId === "codex" || providerId === "gemini" || providerId === "kimi") {
|
|
17173
|
+
if (providerId === "codex" || providerId === "gemini" || providerId === "kimi" || providerId === "grok" || providerId === "copilot") {
|
|
16273
17174
|
const expiresAtMs = oauth.expiresAt ? Date.parse(oauth.expiresAt) : 0;
|
|
16274
17175
|
const expiringSoon = expiresAtMs > 0 && Date.now() >= expiresAtMs - ACCOUNT_REFRESH_LEAD_MS;
|
|
16275
17176
|
if (expiringSoon && oauth.refreshToken) {
|
|
@@ -16373,6 +17274,18 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
16373
17274
|
expiresAt: new Date(Date.now() + r2.expiresIn * 1e3).toISOString()
|
|
16374
17275
|
};
|
|
16375
17276
|
}
|
|
17277
|
+
if (provider === "grok") {
|
|
17278
|
+
const tokenEndpoint = await grokOAuth2.resolveGrokTokenEndpoint(refreshFetch);
|
|
17279
|
+
const r2 = await grokOAuth2.refreshGrokAccessToken(refreshToken, tokenEndpoint, refreshFetch);
|
|
17280
|
+
return {
|
|
17281
|
+
accessToken: r2.accessToken,
|
|
17282
|
+
refreshToken: r2.refreshToken,
|
|
17283
|
+
expiresAt: new Date(Date.now() + r2.expiresIn * 1e3).toISOString()
|
|
17284
|
+
};
|
|
17285
|
+
}
|
|
17286
|
+
if (provider === "copilot") {
|
|
17287
|
+
throw new Error("GitHub Copilot tokens cannot be refreshed \u2014 re-authenticate the account");
|
|
17288
|
+
}
|
|
16376
17289
|
const flow = provider === "claude" ? claudeOAuth2 : provider === "codex" ? codexOAuth2 : geminiOAuth2;
|
|
16377
17290
|
const r = await flow.refreshAccessToken(refreshToken, refreshFetch);
|
|
16378
17291
|
return {
|
|
@@ -16616,7 +17529,7 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
16616
17529
|
};
|
|
16617
17530
|
|
|
16618
17531
|
// src/AccountHealthProbeScheduler.ts
|
|
16619
|
-
import { fetchUpstream as
|
|
17532
|
+
import { fetchUpstream as fetchUpstream10 } from "@omnicross/core/pipeline/upstreamFetch";
|
|
16620
17533
|
|
|
16621
17534
|
// src/probe/CodexGenerationProbe.ts
|
|
16622
17535
|
import {
|
|
@@ -16762,7 +17675,16 @@ var PROVIDER_PROBE_PLANS = {
|
|
|
16762
17675
|
// Kimi's `GET /coding/v1/usages` is a verified FREE authed GET (the allowance
|
|
16763
17676
|
// collector uses it), but the probe path also needs the fingerprint headers —
|
|
16764
17677
|
// keep the probe local until the collector covers the health surface.
|
|
16765
|
-
kimi: { kind: "local" }
|
|
17678
|
+
kimi: { kind: "local" },
|
|
17679
|
+
// Grok's billing proxy is a verified FREE authed GET (the allowance collector
|
|
17680
|
+
// uses it) but it REJECTS non-OAuth credentials and sits on a separate host
|
|
17681
|
+
// with its own product-gate header — keep the probe local, the collector
|
|
17682
|
+
// owns the health surface.
|
|
17683
|
+
grok: { kind: "local" },
|
|
17684
|
+
// The Copilot quota endpoint (copilot_internal/user) is a verified FREE
|
|
17685
|
+
// authed GET but lives on api.github.com with its own auth dialect and a
|
|
17686
|
+
// monthly-only window — the allowance collector owns the health surface.
|
|
17687
|
+
copilot: { kind: "local" }
|
|
16766
17688
|
};
|
|
16767
17689
|
function probePlanFor(providerId) {
|
|
16768
17690
|
return PROVIDER_PROBE_PLANS[providerId] ?? { kind: "local" };
|
|
@@ -16784,7 +17706,7 @@ var AccountHealthProbeScheduler = class {
|
|
|
16784
17706
|
this.logger = logger;
|
|
16785
17707
|
this.config = config;
|
|
16786
17708
|
this.now = opts.now ?? Date.now;
|
|
16787
|
-
this.fetchImpl = opts.fetchImpl ??
|
|
17709
|
+
this.fetchImpl = opts.fetchImpl ?? fetchUpstream10;
|
|
16788
17710
|
this.sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
16789
17711
|
this.planFor = opts.planFor ?? probePlanFor;
|
|
16790
17712
|
}
|
|
@@ -17692,7 +18614,7 @@ async function readAuditStats(auditDir, query2 = {}) {
|
|
|
17692
18614
|
}
|
|
17693
18615
|
|
|
17694
18616
|
// src/audit/AuditPruneSweeper.ts
|
|
17695
|
-
var
|
|
18617
|
+
var DAY_MS4 = 24 * 60 * 6e4;
|
|
17696
18618
|
var SWEEP_INTERVAL_MS2 = 60 * 6e4;
|
|
17697
18619
|
var ARCHIVE_BATCH = 64;
|
|
17698
18620
|
var AuditPruneSweeper = class {
|
|
@@ -17756,7 +18678,7 @@ var AuditPruneSweeper = class {
|
|
|
17756
18678
|
this.sweeping = true;
|
|
17757
18679
|
try {
|
|
17758
18680
|
if (!existsSync25(this.auditDir)) return 0;
|
|
17759
|
-
const cutoff = this.todayMidnight() - (this.config.retentionDays - 1) *
|
|
18681
|
+
const cutoff = this.todayMidnight() - (this.config.retentionDays - 1) * DAY_MS4;
|
|
17760
18682
|
let removed = 0;
|
|
17761
18683
|
for (const name of readdirSync6(this.auditDir)) {
|
|
17762
18684
|
const dateMs = auditFileDateMs(name);
|
|
@@ -18013,7 +18935,7 @@ async function closeAll(writers) {
|
|
|
18013
18935
|
// src/usage/UsagePruneSweeper.ts
|
|
18014
18936
|
import { unlink as unlink3 } from "fs/promises";
|
|
18015
18937
|
import { join as join22 } from "path";
|
|
18016
|
-
var
|
|
18938
|
+
var DAY_MS5 = 24 * 60 * 6e4;
|
|
18017
18939
|
var SWEEP_INTERVAL_MS3 = 60 * 6e4;
|
|
18018
18940
|
var DEFAULT_USAGE_RETENTION_DAYS = 90;
|
|
18019
18941
|
var UsagePruneSweeper = class {
|
|
@@ -18070,7 +18992,7 @@ var UsagePruneSweeper = class {
|
|
|
18070
18992
|
this.sweeping = true;
|
|
18071
18993
|
try {
|
|
18072
18994
|
const retentionDays = this.config.retentionDays ?? DEFAULT_USAGE_RETENTION_DAYS;
|
|
18073
|
-
const cutoff = this.todayMidnight() - (retentionDays - 1) *
|
|
18995
|
+
const cutoff = this.todayMidnight() - (retentionDays - 1) * DAY_MS5;
|
|
18074
18996
|
let removed = 0;
|
|
18075
18997
|
for (const entry of await listUsageDays(this.usageDir)) {
|
|
18076
18998
|
if (!entry.hasShard) continue;
|
|
@@ -18489,7 +19411,7 @@ var AuditWriter = class {
|
|
|
18489
19411
|
import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync8 } from "fs";
|
|
18490
19412
|
import { createHmac as createHmac5 } from "crypto";
|
|
18491
19413
|
import { join as join26 } from "path";
|
|
18492
|
-
import { fetchUpstream as
|
|
19414
|
+
import { fetchUpstream as fetchUpstream11 } from "@omnicross/core/pipeline/upstreamFetch";
|
|
18493
19415
|
|
|
18494
19416
|
// src/billing/billingFiles.ts
|
|
18495
19417
|
var BILLING_FILE_RE = /^billing-(\d{4})-(\d{2})-(\d{2})\.jsonl$/;
|
|
@@ -18512,7 +19434,7 @@ var BillingPublisher = class {
|
|
|
18512
19434
|
constructor(billingDir, logger, opts = {}) {
|
|
18513
19435
|
this.billingDir = billingDir;
|
|
18514
19436
|
this.logger = logger;
|
|
18515
|
-
this.fetchImpl = opts.fetchImpl ?? ((url, init) =>
|
|
19437
|
+
this.fetchImpl = opts.fetchImpl ?? ((url, init) => fetchUpstream11(url, init));
|
|
18516
19438
|
this.defer = opts.defer ?? ((fn) => setTimeout(fn, 0));
|
|
18517
19439
|
this.timeoutMs = opts.timeoutMs ?? BILLING_POST_TIMEOUT_MS;
|
|
18518
19440
|
this.now = opts.now ?? Date.now;
|
|
@@ -18762,7 +19684,7 @@ var BillingRetrySweeper = class {
|
|
|
18762
19684
|
// src/TokenRefreshScheduler.ts
|
|
18763
19685
|
var REFRESH_LEAD_MS2 = 5 * 6e4;
|
|
18764
19686
|
var SWEEP_INTERVAL_MS5 = 6e4;
|
|
18765
|
-
var OAUTH_PROVIDERS2 = ["claude", "codex", "gemini", "kimi"];
|
|
19687
|
+
var OAUTH_PROVIDERS2 = ["claude", "codex", "gemini", "kimi", "grok", "copilot"];
|
|
18766
19688
|
var TokenRefreshScheduler = class {
|
|
18767
19689
|
constructor(store, logger, intervalMs = SWEEP_INTERVAL_MS5, leadMs = REFRESH_LEAD_MS2) {
|
|
18768
19690
|
this.store = store;
|
|
@@ -18847,6 +19769,12 @@ var TokenRefreshScheduler = class {
|
|
|
18847
19769
|
return this.store.refreshGeminiToken();
|
|
18848
19770
|
case "kimi":
|
|
18849
19771
|
return this.store.refreshKimiToken();
|
|
19772
|
+
case "grok":
|
|
19773
|
+
return this.store.refreshGrokToken();
|
|
19774
|
+
// ghu_ tokens never near-expire (far-future expiresAt), so the sweep
|
|
19775
|
+
// never reaches this — the branch exists for union totality.
|
|
19776
|
+
case "copilot":
|
|
19777
|
+
return this.store.refreshCopilotToken();
|
|
18850
19778
|
}
|
|
18851
19779
|
}
|
|
18852
19780
|
};
|
|
@@ -18925,7 +19853,7 @@ function createRouteLeaseSubscriptionPreflight(credentials) {
|
|
|
18925
19853
|
|
|
18926
19854
|
// src/webhook/WebhookDispatcher.ts
|
|
18927
19855
|
import { createHmac as createHmac6 } from "crypto";
|
|
18928
|
-
import { fetchUpstream as
|
|
19856
|
+
import { fetchUpstream as fetchUpstream12 } from "@omnicross/core/pipeline/upstreamFetch";
|
|
18929
19857
|
var WEBHOOK_MAX_ATTEMPTS = 3;
|
|
18930
19858
|
var WEBHOOK_QUEUE_MAX = 1e3;
|
|
18931
19859
|
var WEBHOOK_SEND_TIMEOUT_MS = 1e4;
|
|
@@ -18945,7 +19873,7 @@ var WebhookDispatcher = class {
|
|
|
18945
19873
|
sleep;
|
|
18946
19874
|
now;
|
|
18947
19875
|
constructor(opts = {}) {
|
|
18948
|
-
this.fetchImpl = opts.fetchImpl ?? ((url, init) =>
|
|
19876
|
+
this.fetchImpl = opts.fetchImpl ?? ((url, init) => fetchUpstream12(url, init));
|
|
18949
19877
|
this.logger = opts.logger;
|
|
18950
19878
|
this.maxAttempts = opts.maxAttempts ?? WEBHOOK_MAX_ATTEMPTS;
|
|
18951
19879
|
this.queueMax = opts.queueMax ?? WEBHOOK_QUEUE_MAX;
|
|
@@ -19031,8 +19959,8 @@ var WebhookDispatcher = class {
|
|
|
19031
19959
|
signal: AbortSignal.timeout(this.timeoutMs)
|
|
19032
19960
|
});
|
|
19033
19961
|
return res.ok ? { ok: true, status: res.status } : { ok: false, status: res.status };
|
|
19034
|
-
} catch (
|
|
19035
|
-
return { ok: false, error:
|
|
19962
|
+
} catch (err8) {
|
|
19963
|
+
return { ok: false, error: err8 instanceof Error ? err8.message : String(err8) };
|
|
19036
19964
|
}
|
|
19037
19965
|
}
|
|
19038
19966
|
/**
|
|
@@ -19174,7 +20102,7 @@ function buildDaemon(config, paths) {
|
|
|
19174
20102
|
setSecretBox(secretBox3);
|
|
19175
20103
|
setSecretBox2(secretBox3);
|
|
19176
20104
|
const decryptedConfig = decryptConfigSecrets(config, secretBox3);
|
|
19177
|
-
const accountAllowanceStore = new
|
|
20105
|
+
const accountAllowanceStore = new AccountAllowanceStore8(
|
|
19178
20106
|
Date.now,
|
|
19179
20107
|
void 0,
|
|
19180
20108
|
new JsonAccountAllowancePersistence(defaultAccountAllowancePath(paths.configPath))
|
|
@@ -19236,7 +20164,7 @@ function buildDaemon(config, paths) {
|
|
|
19236
20164
|
const pricingEngine = new PricingEngine(pricingStore, logger, {
|
|
19237
20165
|
// Catalog egress follows the same global/env proxy policy as every other
|
|
19238
20166
|
// daemon upstream call; no provider/account override applies here.
|
|
19239
|
-
fetchImpl: ((input, init) =>
|
|
20167
|
+
fetchImpl: ((input, init) => fetchUpstream13(String(input), init ?? {}))
|
|
19240
20168
|
});
|
|
19241
20169
|
const pricingRefreshScheduler = new PricingRefreshScheduler(
|
|
19242
20170
|
pricingEngine,
|
|
@@ -19521,7 +20449,7 @@ function buildDaemon(config, paths) {
|
|
|
19521
20449
|
// — `server.proxy.byProvider[...]` was silently skipped — and the call was
|
|
19522
20450
|
// excluded from the upstream trace, so a failing login left no evidence.
|
|
19523
20451
|
// `redactBodies` keeps the code/verifier + minted token out of that trace.
|
|
19524
|
-
oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) =>
|
|
20452
|
+
oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => fetchUpstream13(url, init, { providerId, redactBodies: true }),
|
|
19525
20453
|
subscriptionAccountAppender: credentialStore,
|
|
19526
20454
|
// Codex interactive OAuth (app-parity-2 child 5) — the async loopback flow store
|
|
19527
20455
|
// + the one-shot 127.0.0.1:1455 listener. Token captured + persisted daemon-side;
|
|
@@ -19533,6 +20461,9 @@ function buildDaemon(config, paths) {
|
|
|
19533
20461
|
// paste; the app shows the verification URL + user code and polls the
|
|
19534
20462
|
// token-free status). Token captured + persisted daemon-side.
|
|
19535
20463
|
kimiSessions: new CodexOAuthSessionStore(),
|
|
20464
|
+
// Grok interactive OAuth — the same async DEVICE-CODE shape as kimi.
|
|
20465
|
+
grokSessions: new CodexOAuthSessionStore(),
|
|
20466
|
+
copilotSessions: new CodexOAuthSessionStore(),
|
|
19536
20467
|
// Migration pack (app-parity child 6, design D2/D3) — the concrete credential
|
|
19537
20468
|
// store provides BOTH the full DECRYPTED read (`getFullConfig`, export) and
|
|
19538
20469
|
// the multi-account append (`appendProviderAccount`, import re-encrypts at-
|
|
@@ -19591,7 +20522,7 @@ function buildDaemon(config, paths) {
|
|
|
19591
20522
|
});
|
|
19592
20523
|
const webhookDispatcher = new WebhookDispatcher({
|
|
19593
20524
|
logger,
|
|
19594
|
-
fetchImpl: (url, init) =>
|
|
20525
|
+
fetchImpl: (url, init) => fetchUpstream13(url, init)
|
|
19595
20526
|
});
|
|
19596
20527
|
setWebhookRuntime(webhookDispatcher, getSharedAccountHealth4());
|
|
19597
20528
|
const auditWriter = new AuditWriter(auditDir, logger);
|