@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.cjs
CHANGED
|
@@ -62,22 +62,22 @@ var import_node_fs35 = require("fs");
|
|
|
62
62
|
var import_node_path35 = require("path");
|
|
63
63
|
var import_audit_types = require("@omnicross/contracts/audit-types");
|
|
64
64
|
var import_billing_types = require("@omnicross/contracts/billing-types");
|
|
65
|
-
var
|
|
65
|
+
var import_core7 = require("@omnicross/core");
|
|
66
66
|
var import_GeminiCodeAssistProjectResolver = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
|
|
67
67
|
var import_ApiKeyPoolService = require("@omnicross/core/completion/ApiKeyPoolService");
|
|
68
68
|
var import_outbound_api10 = require("@omnicross/core/outbound-api");
|
|
69
69
|
var import_subscriptionRegistryPort = require("@omnicross/core/outbound-api/subscriptionRegistryPort");
|
|
70
70
|
var import_SubscriptionAccountHealth4 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
|
|
71
|
-
var
|
|
71
|
+
var import_AccountAllowanceStore9 = require("@omnicross/core/pipeline/AccountAllowanceStore");
|
|
72
72
|
var import_AccountAllowanceScheduling5 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
|
|
73
|
-
var
|
|
73
|
+
var import_upstreamFetch15 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
74
74
|
var import_SubscriptionIdentityStore3 = require("@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore");
|
|
75
75
|
var import_gemini_code_assist_resolver = require("@omnicross/core/ports/gemini-code-assist-resolver");
|
|
76
76
|
var import_provider_proxy4 = require("@omnicross/core/provider-proxy");
|
|
77
77
|
var import_cli_launcher2 = require("@omnicross/cli-launcher");
|
|
78
78
|
var import_outbound_api11 = require("@omnicross/core/outbound-api");
|
|
79
79
|
var import_usage2 = require("@omnicross/core/usage");
|
|
80
|
-
var
|
|
80
|
+
var import_subscriptions12 = require("@omnicross/subscriptions");
|
|
81
81
|
|
|
82
82
|
// src/admin/accountsCodexOAuth.ts
|
|
83
83
|
var import_node_crypto = __toESM(require("crypto"), 1);
|
|
@@ -259,8 +259,187 @@ function handleKimiOAuthStatus(sessionId, deps) {
|
|
|
259
259
|
return { status: 200, body: { state: s.status, ...s.error ? { message: s.error } : {} } };
|
|
260
260
|
}
|
|
261
261
|
|
|
262
|
+
// src/admin/accountsGrokOAuth.ts
|
|
263
|
+
var import_subscriptions3 = require("@omnicross/subscriptions");
|
|
264
|
+
function err3(status, message) {
|
|
265
|
+
return { status, body: { error: { type: "admin_api_error", message } } };
|
|
266
|
+
}
|
|
267
|
+
var DEFAULT_GROK_OAUTH_TTL_MS = 15 * 6e4;
|
|
268
|
+
async function handleGrokOAuthStart(deps) {
|
|
269
|
+
if (deps.grokSessions.isBusy()) {
|
|
270
|
+
return err3(409, "a grok sign-in is already in progress \u2014 finish it in the browser or cancel it");
|
|
271
|
+
}
|
|
272
|
+
const fetchImpl = deps.oauthExchangeFetch("grok");
|
|
273
|
+
let tokenEndpoint;
|
|
274
|
+
try {
|
|
275
|
+
tokenEndpoint = await import_subscriptions3.grokOAuth.resolveGrokTokenEndpoint(fetchImpl);
|
|
276
|
+
} catch (e) {
|
|
277
|
+
const reason = e instanceof Error ? e.message : "OIDC discovery failed";
|
|
278
|
+
return err3(502, `grok token-endpoint discovery failed: ${reason}`);
|
|
279
|
+
}
|
|
280
|
+
let authorization;
|
|
281
|
+
try {
|
|
282
|
+
authorization = await import_subscriptions3.grokOAuth.requestGrokDeviceAuthorization(fetchImpl);
|
|
283
|
+
} catch (e) {
|
|
284
|
+
const reason = e instanceof Error ? e.message : "device authorization failed";
|
|
285
|
+
return err3(502, `grok device authorization failed: ${reason}`);
|
|
286
|
+
}
|
|
287
|
+
const { sessionId, signal } = deps.grokSessions.begin();
|
|
288
|
+
void runGrokDevicePoll(sessionId, tokenEndpoint, authorization.deviceCode, signal, deps).catch((e) => {
|
|
289
|
+
const reason = e instanceof Error ? e.message : "grok sign-in failed";
|
|
290
|
+
deps.grokSessions.settle(sessionId, "error", reason);
|
|
291
|
+
});
|
|
292
|
+
return {
|
|
293
|
+
status: 200,
|
|
294
|
+
body: {
|
|
295
|
+
authUrl: authorization.verificationUriComplete ?? authorization.verificationUri,
|
|
296
|
+
userCode: authorization.userCode,
|
|
297
|
+
sessionId
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
async function runGrokDevicePoll(sessionId, tokenEndpoint, deviceCode, signal, deps) {
|
|
302
|
+
const fetchImpl = deps.oauthExchangeFetch("grok");
|
|
303
|
+
const result = await import_subscriptions3.grokOAuth.awaitGrokDeviceToken(
|
|
304
|
+
{ userCode: "", deviceCode, verificationUri: "" },
|
|
305
|
+
tokenEndpoint,
|
|
306
|
+
fetchImpl,
|
|
307
|
+
{
|
|
308
|
+
deadlineMs: DEFAULT_GROK_OAUTH_TTL_MS,
|
|
309
|
+
sleep: (ms) => new Promise((resolve10, reject) => {
|
|
310
|
+
const onAbort = () => {
|
|
311
|
+
clearTimeout(timer);
|
|
312
|
+
reject(new Error("login: cancelled"));
|
|
313
|
+
};
|
|
314
|
+
const timer = setTimeout(() => {
|
|
315
|
+
signal.removeEventListener("abort", onAbort);
|
|
316
|
+
resolve10();
|
|
317
|
+
}, ms);
|
|
318
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
319
|
+
})
|
|
320
|
+
}
|
|
321
|
+
);
|
|
322
|
+
const block = {
|
|
323
|
+
authMethod: "oauth",
|
|
324
|
+
status: "authorized",
|
|
325
|
+
accessToken: result.accessToken,
|
|
326
|
+
refreshToken: result.refreshToken,
|
|
327
|
+
expiresAt: new Date(Date.now() + result.expiresIn * 1e3).toISOString(),
|
|
328
|
+
accountId: import_subscriptions3.grokOAuth.grokAccountIdFromAccessToken(result.accessToken),
|
|
329
|
+
lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
330
|
+
};
|
|
331
|
+
await deps.subscriptionAccountAppender.appendProviderAccount("grok", block);
|
|
332
|
+
deps.grokSessions.settle(sessionId, "done");
|
|
333
|
+
}
|
|
334
|
+
function handleGrokOAuthCancel(sessionId, deps) {
|
|
335
|
+
if (!deps.grokSessions.cancel(sessionId)) return err3(404, "unknown or expired grok sign-in session");
|
|
336
|
+
return { status: 200, body: { ok: true } };
|
|
337
|
+
}
|
|
338
|
+
function handleGrokOAuthStatus(sessionId, deps) {
|
|
339
|
+
const s = deps.grokSessions.get(sessionId);
|
|
340
|
+
if (!s) return err3(404, "unknown or expired grok sign-in session");
|
|
341
|
+
return { status: 200, body: { state: s.status, ...s.error ? { message: s.error } : {} } };
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// src/admin/accountsCopilotOAuth.ts
|
|
345
|
+
var import_subscriptions4 = require("@omnicross/subscriptions");
|
|
346
|
+
function err4(status, message) {
|
|
347
|
+
return { status, body: { error: { type: "admin_api_error", message } } };
|
|
348
|
+
}
|
|
349
|
+
var DEFAULT_COPILOT_OAUTH_TTL_MS = 15 * 6e4;
|
|
350
|
+
async function handleCopilotOAuthStart(deps, enterpriseUrlInput) {
|
|
351
|
+
if (deps.copilotSessions.isBusy()) {
|
|
352
|
+
return err4(409, "a copilot sign-in is already in progress \u2014 finish it in the browser or cancel it");
|
|
353
|
+
}
|
|
354
|
+
let enterpriseUrl;
|
|
355
|
+
if (typeof enterpriseUrlInput === "string" && enterpriseUrlInput.trim()) {
|
|
356
|
+
try {
|
|
357
|
+
enterpriseUrl = import_subscriptions4.copilotOAuth.normalizeCopilotEnterpriseDomain(enterpriseUrlInput);
|
|
358
|
+
} catch (e) {
|
|
359
|
+
const reason = e instanceof Error ? e.message : "invalid GitHub Enterprise domain";
|
|
360
|
+
return err4(400, `copilot ${reason}`);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
const fetchImpl = deps.oauthExchangeFetch("copilot");
|
|
364
|
+
let authorization;
|
|
365
|
+
try {
|
|
366
|
+
authorization = await import_subscriptions4.copilotOAuth.requestCopilotDeviceAuthorization(fetchImpl, enterpriseUrl);
|
|
367
|
+
} catch (e) {
|
|
368
|
+
const reason = e instanceof Error ? e.message : "device authorization failed";
|
|
369
|
+
return err4(502, `copilot device authorization failed: ${reason}`);
|
|
370
|
+
}
|
|
371
|
+
const { sessionId, signal } = deps.copilotSessions.begin();
|
|
372
|
+
void runCopilotDevicePoll(sessionId, authorization.deviceCode, signal, deps, enterpriseUrl).catch((e) => {
|
|
373
|
+
const reason = e instanceof Error ? e.message : "copilot sign-in failed";
|
|
374
|
+
deps.copilotSessions.settle(sessionId, "error", reason);
|
|
375
|
+
});
|
|
376
|
+
return {
|
|
377
|
+
status: 200,
|
|
378
|
+
body: {
|
|
379
|
+
authUrl: authorization.verificationUri,
|
|
380
|
+
userCode: authorization.userCode,
|
|
381
|
+
sessionId,
|
|
382
|
+
...enterpriseUrl ? { enterpriseUrl } : {}
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
async function runCopilotDevicePoll(sessionId, deviceCode, signal, deps, enterpriseUrl) {
|
|
387
|
+
const fetchImpl = deps.oauthExchangeFetch("copilot");
|
|
388
|
+
const result = await import_subscriptions4.copilotOAuth.awaitCopilotDeviceToken(
|
|
389
|
+
{ userCode: "", deviceCode, verificationUri: "", interval: 5, expiresIn: 900 },
|
|
390
|
+
fetchImpl,
|
|
391
|
+
{
|
|
392
|
+
deadlineMs: DEFAULT_COPILOT_OAUTH_TTL_MS,
|
|
393
|
+
...enterpriseUrl ? { enterpriseUrl } : {},
|
|
394
|
+
sleep: (ms) => new Promise((resolve10, reject) => {
|
|
395
|
+
const onAbort = () => {
|
|
396
|
+
clearTimeout(timer);
|
|
397
|
+
reject(new Error("login: cancelled"));
|
|
398
|
+
};
|
|
399
|
+
const timer = setTimeout(() => {
|
|
400
|
+
signal.removeEventListener("abort", onAbort);
|
|
401
|
+
resolve10();
|
|
402
|
+
}, ms);
|
|
403
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
404
|
+
})
|
|
405
|
+
}
|
|
406
|
+
);
|
|
407
|
+
const identity = await import_subscriptions4.copilotOAuth.fetchCopilotIdentity(result.accessToken, fetchImpl, enterpriseUrl);
|
|
408
|
+
const apiEndpoint = await import_subscriptions4.copilotOAuth.discoverCopilotApiEndpoint(result.accessToken, fetchImpl, enterpriseUrl);
|
|
409
|
+
await import_subscriptions4.copilotOAuth.enableAllCopilotModels(
|
|
410
|
+
result.accessToken,
|
|
411
|
+
{ apiEndpoint, ...enterpriseUrl ? { enterpriseUrl } : {} },
|
|
412
|
+
fetchImpl
|
|
413
|
+
);
|
|
414
|
+
const block = {
|
|
415
|
+
authMethod: "oauth",
|
|
416
|
+
status: "authorized",
|
|
417
|
+
accessToken: result.accessToken,
|
|
418
|
+
refreshToken: result.accessToken,
|
|
419
|
+
expiresAt: new Date(Date.now() + import_subscriptions4.copilotOAuth.COPILOT_FAR_FUTURE_MS).toISOString(),
|
|
420
|
+
...identity.accountId ? { accountId: identity.accountId } : {},
|
|
421
|
+
...identity.email ? { email: identity.email } : {},
|
|
422
|
+
...apiEndpoint ? { apiEndpoint } : {},
|
|
423
|
+
...enterpriseUrl ? { enterpriseUrl } : {},
|
|
424
|
+
lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
425
|
+
};
|
|
426
|
+
await deps.subscriptionAccountAppender.appendProviderAccount("copilot", block);
|
|
427
|
+
deps.copilotSessions.settle(sessionId, "done");
|
|
428
|
+
}
|
|
429
|
+
function handleCopilotOAuthCancel(sessionId, deps) {
|
|
430
|
+
if (!deps.copilotSessions.cancel(sessionId)) {
|
|
431
|
+
return err4(404, "unknown or expired copilot sign-in session");
|
|
432
|
+
}
|
|
433
|
+
return { status: 200, body: { ok: true } };
|
|
434
|
+
}
|
|
435
|
+
function handleCopilotOAuthStatus(sessionId, deps) {
|
|
436
|
+
const s = deps.copilotSessions.get(sessionId);
|
|
437
|
+
if (!s) return err4(404, "unknown or expired copilot sign-in session");
|
|
438
|
+
return { status: 200, body: { state: s.status, ...s.error ? { message: s.error } : {} } };
|
|
439
|
+
}
|
|
440
|
+
|
|
262
441
|
// src/allowance/AccountAllowanceService.ts
|
|
263
|
-
var
|
|
442
|
+
var import_AccountAllowanceStore7 = require("@omnicross/core/pipeline/AccountAllowanceStore");
|
|
264
443
|
var import_AccountAllowanceScheduling = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
|
|
265
444
|
|
|
266
445
|
// src/allowance/ClaudeAllowanceCollector.ts
|
|
@@ -731,7 +910,7 @@ var CodexAllowanceCollector = class {
|
|
|
731
910
|
// src/allowance/KimiAllowanceCollector.ts
|
|
732
911
|
var import_AccountAllowanceStore3 = require("@omnicross/core/pipeline/AccountAllowanceStore");
|
|
733
912
|
var import_upstreamFetch3 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
734
|
-
var
|
|
913
|
+
var import_subscriptions5 = require("@omnicross/subscriptions");
|
|
735
914
|
var KIMI_ALLOWANCE_CACHE_MS = 5 * 6e4;
|
|
736
915
|
var KIMI_USAGE_URL = "https://api.kimi.com/coding/v1/usages";
|
|
737
916
|
function finiteNumber2(value) {
|
|
@@ -823,24 +1002,501 @@ function parseKimiUsagePayload(payload, now) {
|
|
|
823
1002
|
const window = windowFromRow({ ...row, resetsAtMs: row.resetsAtMs }, { id: "seven-day", label: "7 days", minutes: 10080 }, now);
|
|
824
1003
|
byId.set("seven-day", window);
|
|
825
1004
|
}
|
|
826
|
-
if (Array.isArray(payload["limits"])) {
|
|
827
|
-
for (const item of payload["limits"]) {
|
|
828
|
-
if (!isRecord(item)) continue;
|
|
829
|
-
const detail = isRecord(item["detail"]) ? item["detail"] : item;
|
|
830
|
-
const row = rowFrom(detail);
|
|
831
|
-
const canonical = row.windowDurationMs !== void 0 ? canonicalWindow(row.windowDurationMs) : void 0;
|
|
832
|
-
if (!canonical) continue;
|
|
833
|
-
const window = windowFromRow(row, canonical, now);
|
|
834
|
-
const existing = byId.get(canonical.id);
|
|
835
|
-
if (!existing || (window.usedPercent ?? 0) > (existing.usedPercent ?? 0)) {
|
|
836
|
-
byId.set(canonical.id, window);
|
|
837
|
-
}
|
|
1005
|
+
if (Array.isArray(payload["limits"])) {
|
|
1006
|
+
for (const item of payload["limits"]) {
|
|
1007
|
+
if (!isRecord(item)) continue;
|
|
1008
|
+
const detail = isRecord(item["detail"]) ? item["detail"] : item;
|
|
1009
|
+
const row = rowFrom(detail);
|
|
1010
|
+
const canonical = row.windowDurationMs !== void 0 ? canonicalWindow(row.windowDurationMs) : void 0;
|
|
1011
|
+
if (!canonical) continue;
|
|
1012
|
+
const window = windowFromRow(row, canonical, now);
|
|
1013
|
+
const existing = byId.get(canonical.id);
|
|
1014
|
+
if (!existing || (window.usedPercent ?? 0) > (existing.usedPercent ?? 0)) {
|
|
1015
|
+
byId.set(canonical.id, window);
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
return [...byId.values()].sort((a, b) => (a.windowMinutes ?? Infinity) - (b.windowMinutes ?? Infinity)).slice(0, 4);
|
|
1020
|
+
}
|
|
1021
|
+
var KimiAllowanceCollector = class {
|
|
1022
|
+
constructor(credentials, store = (0, import_AccountAllowanceStore3.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch3.fetchUpstream)(url, init, { providerId: "kimi", accountId, redactBodies: true }), now = Date.now) {
|
|
1023
|
+
this.credentials = credentials;
|
|
1024
|
+
this.store = store;
|
|
1025
|
+
this.fetchImpl = fetchImpl;
|
|
1026
|
+
this.now = now;
|
|
1027
|
+
}
|
|
1028
|
+
credentials;
|
|
1029
|
+
store;
|
|
1030
|
+
fetchImpl;
|
|
1031
|
+
now;
|
|
1032
|
+
inFlight = /* @__PURE__ */ new Map();
|
|
1033
|
+
async collectMany(accounts, options = {}) {
|
|
1034
|
+
const settled = await Promise.allSettled(accounts.map((account) => this.collect(account, options)));
|
|
1035
|
+
return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
|
|
1036
|
+
}
|
|
1037
|
+
collect(account, options = {}) {
|
|
1038
|
+
const now = this.now();
|
|
1039
|
+
if (account.tokens.authMethod !== "oauth") {
|
|
1040
|
+
const existing = this.store.get("kimi", account.id, now);
|
|
1041
|
+
if (existing?.windows.every((window) => window.state === "unsupported")) {
|
|
1042
|
+
return Promise.resolve(existing);
|
|
1043
|
+
}
|
|
1044
|
+
const snapshot = this.unsupportedSnapshot(account.id, now);
|
|
1045
|
+
this.store.set(snapshot);
|
|
1046
|
+
return Promise.resolve(snapshot);
|
|
1047
|
+
}
|
|
1048
|
+
const cached = this.store.get("kimi", account.id, now);
|
|
1049
|
+
if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) {
|
|
1050
|
+
return Promise.resolve(cached);
|
|
1051
|
+
}
|
|
1052
|
+
const running = this.inFlight.get(account.id);
|
|
1053
|
+
if (running) return running;
|
|
1054
|
+
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));
|
|
1055
|
+
this.inFlight.set(account.id, promise);
|
|
1056
|
+
return promise;
|
|
1057
|
+
}
|
|
1058
|
+
isCacheValid(snapshot, now, refreshAheadMs) {
|
|
1059
|
+
if (snapshot.windows.every((window) => window.state === "unsupported")) return true;
|
|
1060
|
+
const expiresAt = snapshot.expiresAt ? Date.parse(snapshot.expiresAt) : 0;
|
|
1061
|
+
const ahead = typeof refreshAheadMs === "number" && Number.isFinite(refreshAheadMs) ? Math.max(0, refreshAheadMs) : 0;
|
|
1062
|
+
return Number.isFinite(expiresAt) && expiresAt > now + ahead;
|
|
1063
|
+
}
|
|
1064
|
+
async fetchAccount(accountId, tokens) {
|
|
1065
|
+
let accessToken = await this.credentials.getAccessTokenForAccount("kimi", accountId);
|
|
1066
|
+
if (!accessToken) return this.failureSnapshot(accountId, "kimi_usage_token_unavailable", this.now());
|
|
1067
|
+
let response = await this.request(accountId, accessToken, tokens);
|
|
1068
|
+
if (response.status === 401) {
|
|
1069
|
+
const refreshed = await this.credentials.refreshAccountToken("kimi", accountId);
|
|
1070
|
+
if (!refreshed) return this.failureSnapshot(accountId, "kimi_usage_unauthorized", this.now());
|
|
1071
|
+
accessToken = await this.credentials.getAccessTokenForAccount("kimi", accountId);
|
|
1072
|
+
if (!accessToken) return this.failureSnapshot(accountId, "kimi_usage_token_unavailable", this.now());
|
|
1073
|
+
response = await this.request(accountId, accessToken, tokens);
|
|
1074
|
+
}
|
|
1075
|
+
if (response.status === 403) {
|
|
1076
|
+
const snapshot2 = this.unsupportedSnapshot(accountId, this.now(), "kimi_usage_unsupported");
|
|
1077
|
+
this.store.set(snapshot2);
|
|
1078
|
+
return snapshot2;
|
|
1079
|
+
}
|
|
1080
|
+
if (!response.ok) return this.failureSnapshot(accountId, "kimi_usage_http_error", this.now());
|
|
1081
|
+
let payload;
|
|
1082
|
+
try {
|
|
1083
|
+
payload = await response.json();
|
|
1084
|
+
} catch {
|
|
1085
|
+
return this.failureSnapshot(accountId, "kimi_usage_invalid_response", this.now());
|
|
1086
|
+
}
|
|
1087
|
+
const now = this.now();
|
|
1088
|
+
const windows = parseKimiUsagePayload(payload, now);
|
|
1089
|
+
const snapshot = {
|
|
1090
|
+
providerId: "kimi",
|
|
1091
|
+
accountId,
|
|
1092
|
+
source: "oauth-usage-api",
|
|
1093
|
+
observedAt: new Date(now).toISOString(),
|
|
1094
|
+
expiresAt: new Date(now + KIMI_ALLOWANCE_CACHE_MS).toISOString(),
|
|
1095
|
+
windows: windows.length > 0 ? windows : [
|
|
1096
|
+
{ id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unavailable" },
|
|
1097
|
+
{ id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" }
|
|
1098
|
+
],
|
|
1099
|
+
...windows.length > 0 ? {} : { lastErrorCode: "kimi_usage_invalid_response" }
|
|
1100
|
+
};
|
|
1101
|
+
this.store.set(snapshot);
|
|
1102
|
+
return snapshot;
|
|
1103
|
+
}
|
|
1104
|
+
request(accountId, accessToken, tokens) {
|
|
1105
|
+
return this.fetchImpl(KIMI_USAGE_URL, {
|
|
1106
|
+
method: "GET",
|
|
1107
|
+
headers: {
|
|
1108
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1109
|
+
Accept: "application/json",
|
|
1110
|
+
...(0, import_subscriptions5.kimiFingerprintHeaders)(tokens.deviceId)
|
|
1111
|
+
},
|
|
1112
|
+
signal: AbortSignal.timeout(15e3)
|
|
1113
|
+
}, accountId);
|
|
1114
|
+
}
|
|
1115
|
+
failureSnapshot(accountId, code, now) {
|
|
1116
|
+
const existing = this.store.get("kimi", accountId, now);
|
|
1117
|
+
const snapshot = existing ? {
|
|
1118
|
+
...existing,
|
|
1119
|
+
expiresAt: new Date(now + KIMI_ALLOWANCE_CACHE_MS).toISOString(),
|
|
1120
|
+
windows: existing.windows.map((window) => ({
|
|
1121
|
+
...window,
|
|
1122
|
+
state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt ? "stale" : "unavailable"
|
|
1123
|
+
})),
|
|
1124
|
+
lastErrorCode: code
|
|
1125
|
+
} : {
|
|
1126
|
+
providerId: "kimi",
|
|
1127
|
+
accountId,
|
|
1128
|
+
source: "oauth-usage-api",
|
|
1129
|
+
observedAt: new Date(now).toISOString(),
|
|
1130
|
+
expiresAt: new Date(now + KIMI_ALLOWANCE_CACHE_MS).toISOString(),
|
|
1131
|
+
windows: [
|
|
1132
|
+
{ id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unavailable" },
|
|
1133
|
+
{ id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" }
|
|
1134
|
+
],
|
|
1135
|
+
lastErrorCode: code
|
|
1136
|
+
};
|
|
1137
|
+
this.store.set(snapshot);
|
|
1138
|
+
return snapshot;
|
|
1139
|
+
}
|
|
1140
|
+
unsupportedSnapshot(accountId, now, code = "kimi_usage_unsupported_auth") {
|
|
1141
|
+
return {
|
|
1142
|
+
providerId: "kimi",
|
|
1143
|
+
accountId,
|
|
1144
|
+
source: "oauth-usage-api",
|
|
1145
|
+
observedAt: new Date(now).toISOString(),
|
|
1146
|
+
windows: [
|
|
1147
|
+
{ id: "five-hour", label: "5 hours", scope: "all", usedPercent: null, state: "unsupported" },
|
|
1148
|
+
{ id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unsupported" }
|
|
1149
|
+
],
|
|
1150
|
+
lastErrorCode: code
|
|
1151
|
+
};
|
|
1152
|
+
}
|
|
1153
|
+
};
|
|
1154
|
+
|
|
1155
|
+
// src/allowance/GrokAllowanceCollector.ts
|
|
1156
|
+
var import_AccountAllowanceStore4 = require("@omnicross/core/pipeline/AccountAllowanceStore");
|
|
1157
|
+
var import_upstreamFetch4 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
1158
|
+
var GROK_ALLOWANCE_CACHE_MS = 5 * 6e4;
|
|
1159
|
+
var GROK_BILLING_BASE = "https://cli-chat-proxy.grok.com";
|
|
1160
|
+
var GROK_BILLING_CREDITS_URL = `${GROK_BILLING_BASE}/v1/billing?format=credits`;
|
|
1161
|
+
var GROK_BILLING_MONTHLY_URL = `${GROK_BILLING_BASE}/v1/billing`;
|
|
1162
|
+
function isRecord2(value) {
|
|
1163
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
1164
|
+
}
|
|
1165
|
+
function finiteNumber3(value) {
|
|
1166
|
+
if (value === null || value === void 0 || value === "") return void 0;
|
|
1167
|
+
const parsed = typeof value === "number" ? value : Number(value);
|
|
1168
|
+
return Number.isFinite(parsed) && parsed >= 0 ? parsed : void 0;
|
|
1169
|
+
}
|
|
1170
|
+
function percent(value) {
|
|
1171
|
+
const parsed = finiteNumber3(value);
|
|
1172
|
+
return parsed !== void 0 && parsed <= 100 ? parsed : void 0;
|
|
1173
|
+
}
|
|
1174
|
+
function onDemandAmount(value) {
|
|
1175
|
+
return isRecord2(value) ? finiteNumber3(value["val"]) : void 0;
|
|
1176
|
+
}
|
|
1177
|
+
function confirmsNoMonthlyQuota(raw) {
|
|
1178
|
+
const limit = onDemandAmount(raw["monthlyLimit"]);
|
|
1179
|
+
if (limit !== void 0) return limit === 0;
|
|
1180
|
+
return parseWeeklyConfig(raw)?.inferredPercent === true;
|
|
1181
|
+
}
|
|
1182
|
+
function parseWeeklyConfig(raw) {
|
|
1183
|
+
const period = isRecord2(raw["currentPeriod"]) ? raw["currentPeriod"] : void 0;
|
|
1184
|
+
if (!period) return null;
|
|
1185
|
+
const start = typeof period["start"] === "string" ? Date.parse(period["start"]) : Number.NaN;
|
|
1186
|
+
const end = typeof period["end"] === "string" ? Date.parse(period["end"]) : Number.NaN;
|
|
1187
|
+
const type = typeof period["type"] === "string" ? period["type"] : "";
|
|
1188
|
+
if (!Number.isFinite(start) || !Number.isFinite(end) || end <= start) return null;
|
|
1189
|
+
if (!type.toUpperCase().includes("WEEK")) return null;
|
|
1190
|
+
const inferred = raw["creditUsagePercent"] === void 0 || raw["creditUsagePercent"] === null;
|
|
1191
|
+
let creditUsagePercent;
|
|
1192
|
+
if (inferred) {
|
|
1193
|
+
creditUsagePercent = end > Date.now() ? 0 : void 0;
|
|
1194
|
+
} else {
|
|
1195
|
+
creditUsagePercent = percent(raw["creditUsagePercent"]);
|
|
1196
|
+
}
|
|
1197
|
+
if (creditUsagePercent === void 0) return null;
|
|
1198
|
+
return {
|
|
1199
|
+
creditUsagePercent,
|
|
1200
|
+
inferredPercent: inferred,
|
|
1201
|
+
resetsAtMs: end,
|
|
1202
|
+
unified: raw["isUnifiedBillingUser"] === true
|
|
1203
|
+
};
|
|
1204
|
+
}
|
|
1205
|
+
function parseMonthlyConfig(raw) {
|
|
1206
|
+
const start = typeof raw["billingPeriodStart"] === "string" ? Date.parse(raw["billingPeriodStart"]) : Number.NaN;
|
|
1207
|
+
const end = typeof raw["billingPeriodEnd"] === "string" ? Date.parse(raw["billingPeriodEnd"]) : Number.NaN;
|
|
1208
|
+
if (!Number.isFinite(start) || !Number.isFinite(end) || end <= start) return null;
|
|
1209
|
+
const limit = onDemandAmount(raw["monthlyLimit"]);
|
|
1210
|
+
const used = onDemandAmount(raw["used"]);
|
|
1211
|
+
if (limit === void 0 || limit <= 0 || used === void 0) return null;
|
|
1212
|
+
return { used, limit, periodStartMs: start, periodEndMs: end };
|
|
1213
|
+
}
|
|
1214
|
+
function secondsUntil4(instant, now) {
|
|
1215
|
+
if (!instant) return void 0;
|
|
1216
|
+
return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
|
|
1217
|
+
}
|
|
1218
|
+
var MINUTE_MS2 = 6e4;
|
|
1219
|
+
var DAY_MS2 = 864e5;
|
|
1220
|
+
var WEEK_MINUTES = 7 * 24 * 60;
|
|
1221
|
+
function weeklyWindow(config, now) {
|
|
1222
|
+
const resetsAt = new Date(config.resetsAtMs).toISOString();
|
|
1223
|
+
return {
|
|
1224
|
+
id: "seven-day",
|
|
1225
|
+
label: "7 days",
|
|
1226
|
+
scope: "all",
|
|
1227
|
+
usedPercent: config.creditUsagePercent,
|
|
1228
|
+
windowMinutes: WEEK_MINUTES,
|
|
1229
|
+
resetsAt,
|
|
1230
|
+
remainingSeconds: secondsUntil4(resetsAt, now),
|
|
1231
|
+
state: "fresh"
|
|
1232
|
+
};
|
|
1233
|
+
}
|
|
1234
|
+
function monthlyWindow(config, now) {
|
|
1235
|
+
const resetsAt = new Date(config.periodEndMs).toISOString();
|
|
1236
|
+
const days = Math.max(1, Math.round((config.periodEndMs - config.periodStartMs) / DAY_MS2));
|
|
1237
|
+
return {
|
|
1238
|
+
id: "thirty-day",
|
|
1239
|
+
label: days === 30 || days === 31 ? "30 days" : `${days} days`,
|
|
1240
|
+
scope: "all",
|
|
1241
|
+
usedPercent: Math.round(Math.min(100, config.used / config.limit * 100) * 10) / 10,
|
|
1242
|
+
windowMinutes: Math.round((config.periodEndMs - config.periodStartMs) / MINUTE_MS2),
|
|
1243
|
+
resetsAt,
|
|
1244
|
+
remainingSeconds: secondsUntil4(resetsAt, now),
|
|
1245
|
+
state: "fresh"
|
|
1246
|
+
};
|
|
1247
|
+
}
|
|
1248
|
+
function onDemandWindow(raw) {
|
|
1249
|
+
const cap = onDemandAmount(raw["onDemandCap"]);
|
|
1250
|
+
const used = onDemandAmount(raw["onDemandUsed"]);
|
|
1251
|
+
if (cap === void 0 || cap <= 0 || used === void 0) return null;
|
|
1252
|
+
return {
|
|
1253
|
+
id: "on-demand",
|
|
1254
|
+
label: "On-demand",
|
|
1255
|
+
scope: "all",
|
|
1256
|
+
usedPercent: Math.round(Math.min(100, used / cap * 100) * 10) / 10,
|
|
1257
|
+
state: "fresh"
|
|
1258
|
+
};
|
|
1259
|
+
}
|
|
1260
|
+
async function probeBilling(url, accessToken, accountId, fetchImpl) {
|
|
1261
|
+
try {
|
|
1262
|
+
const response = await fetchImpl(url, {
|
|
1263
|
+
method: "GET",
|
|
1264
|
+
headers: {
|
|
1265
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1266
|
+
Accept: "application/json",
|
|
1267
|
+
"X-XAI-Token-Auth": "xai-grok-cli"
|
|
1268
|
+
},
|
|
1269
|
+
redirect: "error",
|
|
1270
|
+
signal: AbortSignal.timeout(15e3)
|
|
1271
|
+
}, accountId);
|
|
1272
|
+
if (!response.ok) return { status: response.status, payload: null };
|
|
1273
|
+
const payload = await response.json();
|
|
1274
|
+
return { status: response.status, payload: isRecord2(payload) ? payload : null };
|
|
1275
|
+
} catch {
|
|
1276
|
+
return { status: 0, payload: null };
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
function parseGrokBillingPayloads(creditsPayload, monthlyPayload, now) {
|
|
1280
|
+
const creditsConfig = isRecord2(creditsPayload?.["config"]) ? creditsPayload["config"] : null;
|
|
1281
|
+
const monthlyConfig = isRecord2(monthlyPayload?.["config"]) ? monthlyPayload["config"] : null;
|
|
1282
|
+
let weekly = creditsConfig ? parseWeeklyConfig(creditsConfig) : null;
|
|
1283
|
+
const unifiedFlag = creditsConfig?.["isUnifiedBillingUser"] === true;
|
|
1284
|
+
let monthly = monthlyConfig ? parseMonthlyConfig(monthlyConfig) : null;
|
|
1285
|
+
if (weekly?.inferredPercent && unifiedFlag) {
|
|
1286
|
+
if (monthly) {
|
|
1287
|
+
weekly = null;
|
|
1288
|
+
} else if (!monthlyConfig || !confirmsNoMonthlyQuota(monthlyConfig)) {
|
|
1289
|
+
weekly = null;
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
const windows = [];
|
|
1293
|
+
if (weekly) windows.push(weeklyWindow(weekly, now));
|
|
1294
|
+
if (monthly) windows.push(monthlyWindow(monthly, now));
|
|
1295
|
+
const onDemandSource = monthly && monthlyConfig ? monthlyConfig : creditsConfig;
|
|
1296
|
+
const onDemand = onDemandSource ? onDemandWindow(onDemandSource) : null;
|
|
1297
|
+
if (onDemand) windows.push(onDemand);
|
|
1298
|
+
return windows.length > 0 ? windows : null;
|
|
1299
|
+
}
|
|
1300
|
+
var GrokAllowanceCollector = class {
|
|
1301
|
+
constructor(credentials, store = (0, import_AccountAllowanceStore4.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch4.fetchUpstream)(url, init, { providerId: "grok", accountId, redactBodies: true }), now = Date.now) {
|
|
1302
|
+
this.credentials = credentials;
|
|
1303
|
+
this.store = store;
|
|
1304
|
+
this.fetchImpl = fetchImpl;
|
|
1305
|
+
this.now = now;
|
|
1306
|
+
}
|
|
1307
|
+
credentials;
|
|
1308
|
+
store;
|
|
1309
|
+
fetchImpl;
|
|
1310
|
+
now;
|
|
1311
|
+
inFlight = /* @__PURE__ */ new Map();
|
|
1312
|
+
async collectMany(accounts, options = {}) {
|
|
1313
|
+
const settled = await Promise.allSettled(accounts.map((account) => this.collect(account, options)));
|
|
1314
|
+
return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
|
|
1315
|
+
}
|
|
1316
|
+
collect(account, options = {}) {
|
|
1317
|
+
const now = this.now();
|
|
1318
|
+
if (account.tokens.authMethod !== "oauth") {
|
|
1319
|
+
const existing = this.store.get("grok", account.id, now);
|
|
1320
|
+
if (existing?.windows.every((window) => window.state === "unsupported")) {
|
|
1321
|
+
return Promise.resolve(existing);
|
|
1322
|
+
}
|
|
1323
|
+
const snapshot = this.unsupportedSnapshot(account.id, now);
|
|
1324
|
+
this.store.set(snapshot);
|
|
1325
|
+
return Promise.resolve(snapshot);
|
|
1326
|
+
}
|
|
1327
|
+
const cached = this.store.get("grok", account.id, now);
|
|
1328
|
+
if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) {
|
|
1329
|
+
return Promise.resolve(cached);
|
|
1330
|
+
}
|
|
1331
|
+
const running = this.inFlight.get(account.id);
|
|
1332
|
+
if (running) return running;
|
|
1333
|
+
const promise = this.fetchAccount(account.id).catch(() => this.failureSnapshot(account.id, "grok_usage_request_failed", this.now())).finally(() => this.inFlight.delete(account.id));
|
|
1334
|
+
this.inFlight.set(account.id, promise);
|
|
1335
|
+
return promise;
|
|
1336
|
+
}
|
|
1337
|
+
isCacheValid(snapshot, now, refreshAheadMs) {
|
|
1338
|
+
if (snapshot.windows.every((window) => window.state === "unsupported")) return true;
|
|
1339
|
+
const expiresAt = snapshot.expiresAt ? Date.parse(snapshot.expiresAt) : 0;
|
|
1340
|
+
const ahead = typeof refreshAheadMs === "number" && Number.isFinite(refreshAheadMs) ? Math.max(0, refreshAheadMs) : 0;
|
|
1341
|
+
return Number.isFinite(expiresAt) && expiresAt > now + ahead;
|
|
1342
|
+
}
|
|
1343
|
+
async fetchAccount(accountId) {
|
|
1344
|
+
const probe = async () => {
|
|
1345
|
+
const accessToken = await this.credentials.getAccessTokenForAccount("grok", accountId);
|
|
1346
|
+
if (!accessToken) return { unauthorized: true, windows: null };
|
|
1347
|
+
const credits = await probeBilling(GROK_BILLING_CREDITS_URL, accessToken, accountId, this.fetchImpl);
|
|
1348
|
+
if (credits.status === 401 || credits.status === 403) return { unauthorized: true, windows: null };
|
|
1349
|
+
const creditsConfig = isRecord2(credits.payload?.["config"]) ? credits.payload["config"] : null;
|
|
1350
|
+
const weekly = creditsConfig ? parseWeeklyConfig(creditsConfig) : null;
|
|
1351
|
+
const monthly = !weekly || creditsConfig?.["isUnifiedBillingUser"] === true ? await probeBilling(GROK_BILLING_MONTHLY_URL, accessToken, accountId, this.fetchImpl) : { status: 200, payload: null };
|
|
1352
|
+
if (monthly.status === 401 || monthly.status === 403) return { unauthorized: true, windows: null };
|
|
1353
|
+
return {
|
|
1354
|
+
unauthorized: false,
|
|
1355
|
+
windows: parseGrokBillingPayloads(credits.payload, monthly.payload, this.now())
|
|
1356
|
+
};
|
|
1357
|
+
};
|
|
1358
|
+
let result = await probe();
|
|
1359
|
+
if (result.unauthorized) {
|
|
1360
|
+
const refreshed = await this.credentials.refreshAccountToken("grok", accountId);
|
|
1361
|
+
if (!refreshed) return this.failureSnapshot(accountId, "grok_usage_unauthorized", this.now());
|
|
1362
|
+
result = await probe();
|
|
1363
|
+
if (result.unauthorized) {
|
|
1364
|
+
return this.failureSnapshot(accountId, "grok_usage_unauthorized", this.now());
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
const now = this.now();
|
|
1368
|
+
if (result.windows && result.windows.length > 0) {
|
|
1369
|
+
const snapshot = {
|
|
1370
|
+
providerId: "grok",
|
|
1371
|
+
accountId,
|
|
1372
|
+
source: "oauth-usage-api",
|
|
1373
|
+
observedAt: new Date(now).toISOString(),
|
|
1374
|
+
expiresAt: new Date(now + GROK_ALLOWANCE_CACHE_MS).toISOString(),
|
|
1375
|
+
windows: result.windows
|
|
1376
|
+
};
|
|
1377
|
+
this.store.set(snapshot);
|
|
1378
|
+
return snapshot;
|
|
1379
|
+
}
|
|
1380
|
+
return this.failureSnapshot(accountId, "grok_usage_invalid_response", now);
|
|
1381
|
+
}
|
|
1382
|
+
failureSnapshot(accountId, code, now) {
|
|
1383
|
+
const existing = this.store.get("grok", accountId, now);
|
|
1384
|
+
const snapshot = existing ? {
|
|
1385
|
+
...existing,
|
|
1386
|
+
expiresAt: new Date(now + GROK_ALLOWANCE_CACHE_MS).toISOString(),
|
|
1387
|
+
windows: existing.windows.map((window) => ({
|
|
1388
|
+
...window,
|
|
1389
|
+
state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt ? "stale" : "unavailable"
|
|
1390
|
+
})),
|
|
1391
|
+
lastErrorCode: code
|
|
1392
|
+
} : {
|
|
1393
|
+
providerId: "grok",
|
|
1394
|
+
accountId,
|
|
1395
|
+
source: "oauth-usage-api",
|
|
1396
|
+
observedAt: new Date(now).toISOString(),
|
|
1397
|
+
expiresAt: new Date(now + GROK_ALLOWANCE_CACHE_MS).toISOString(),
|
|
1398
|
+
windows: [
|
|
1399
|
+
{ id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" },
|
|
1400
|
+
{ id: "thirty-day", label: "30 days", scope: "all", usedPercent: null, state: "unavailable" }
|
|
1401
|
+
],
|
|
1402
|
+
lastErrorCode: code
|
|
1403
|
+
};
|
|
1404
|
+
this.store.set(snapshot);
|
|
1405
|
+
return snapshot;
|
|
1406
|
+
}
|
|
1407
|
+
unsupportedSnapshot(accountId, now) {
|
|
1408
|
+
return {
|
|
1409
|
+
providerId: "grok",
|
|
1410
|
+
accountId,
|
|
1411
|
+
source: "oauth-usage-api",
|
|
1412
|
+
observedAt: new Date(now).toISOString(),
|
|
1413
|
+
windows: [
|
|
1414
|
+
{ id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unsupported" },
|
|
1415
|
+
{ id: "thirty-day", label: "30 days", scope: "all", usedPercent: null, state: "unsupported" }
|
|
1416
|
+
],
|
|
1417
|
+
lastErrorCode: "grok_usage_unsupported_auth"
|
|
1418
|
+
};
|
|
1419
|
+
}
|
|
1420
|
+
};
|
|
1421
|
+
|
|
1422
|
+
// src/allowance/CopilotAllowanceCollector.ts
|
|
1423
|
+
var import_AccountAllowanceStore5 = require("@omnicross/core/pipeline/AccountAllowanceStore");
|
|
1424
|
+
var import_upstreamFetch5 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
1425
|
+
var import_subscriptions6 = require("@omnicross/subscriptions");
|
|
1426
|
+
var COPILOT_ALLOWANCE_CACHE_MS = 5 * 6e4;
|
|
1427
|
+
function isRecord3(value) {
|
|
1428
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
1429
|
+
}
|
|
1430
|
+
function finiteNumber4(value) {
|
|
1431
|
+
if (value === null || value === void 0 || value === "") return void 0;
|
|
1432
|
+
const parsed = typeof value === "number" ? value : Number(value);
|
|
1433
|
+
return Number.isFinite(parsed) && parsed >= 0 ? parsed : void 0;
|
|
1434
|
+
}
|
|
1435
|
+
function booleanValue(value) {
|
|
1436
|
+
if (typeof value === "boolean") return value;
|
|
1437
|
+
if (value === "true") return true;
|
|
1438
|
+
if (value === "false") return false;
|
|
1439
|
+
return void 0;
|
|
1440
|
+
}
|
|
1441
|
+
function parseQuotaDetail(value) {
|
|
1442
|
+
if (!isRecord3(value)) return null;
|
|
1443
|
+
const entitlement = finiteNumber4(value["entitlement"]);
|
|
1444
|
+
const remaining = finiteNumber4(value["remaining"]);
|
|
1445
|
+
const percentRemaining = finiteNumber4(value["percent_remaining"]);
|
|
1446
|
+
const unlimited = booleanValue(value["unlimited"]);
|
|
1447
|
+
if (entitlement === void 0 || remaining === void 0 || percentRemaining === void 0 || unlimited === void 0) {
|
|
1448
|
+
return null;
|
|
1449
|
+
}
|
|
1450
|
+
return { entitlement, remaining, percentRemaining, unlimited };
|
|
1451
|
+
}
|
|
1452
|
+
function secondsUntil5(instant, now) {
|
|
1453
|
+
if (!instant) return void 0;
|
|
1454
|
+
return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
|
|
1455
|
+
}
|
|
1456
|
+
function parseCopilotUserPayload(payload, now) {
|
|
1457
|
+
if (!isRecord3(payload)) return null;
|
|
1458
|
+
const snapshots = isRecord3(payload["quota_snapshots"]) ? payload["quota_snapshots"] : void 0;
|
|
1459
|
+
if (!snapshots) return null;
|
|
1460
|
+
const resetRaw = payload["quota_reset_date"];
|
|
1461
|
+
const resetsAt = typeof resetRaw === "string" && resetRaw.trim() && Number.isFinite(Date.parse(resetRaw)) ? new Date(Date.parse(resetRaw)).toISOString() : void 0;
|
|
1462
|
+
const windows = [];
|
|
1463
|
+
const premium = parseQuotaDetail(snapshots["premium_interactions"]);
|
|
1464
|
+
if (premium) {
|
|
1465
|
+
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;
|
|
1466
|
+
if (usedPercent !== null) {
|
|
1467
|
+
windows.push({
|
|
1468
|
+
id: "thirty-day",
|
|
1469
|
+
label: "Monthly",
|
|
1470
|
+
scope: "all",
|
|
1471
|
+
usedPercent,
|
|
1472
|
+
windowMinutes: 30 * 24 * 60,
|
|
1473
|
+
...resetsAt !== void 0 ? { resetsAt } : {},
|
|
1474
|
+
remainingSeconds: secondsUntil5(resetsAt, now),
|
|
1475
|
+
state: "fresh"
|
|
1476
|
+
});
|
|
838
1477
|
}
|
|
839
1478
|
}
|
|
840
|
-
|
|
1479
|
+
const chat = parseQuotaDetail(snapshots["chat"]);
|
|
1480
|
+
if (chat && !chat.unlimited && chat.entitlement > 0) {
|
|
1481
|
+
const usedPercent = Math.round(Math.min(100, (chat.entitlement - chat.remaining) / chat.entitlement * 100) * 10) / 10;
|
|
1482
|
+
windows.push({
|
|
1483
|
+
id: "chat-monthly",
|
|
1484
|
+
label: "Chat (monthly)",
|
|
1485
|
+
scope: "all",
|
|
1486
|
+
usedPercent,
|
|
1487
|
+
windowMinutes: 30 * 24 * 60,
|
|
1488
|
+
...resetsAt !== void 0 ? { resetsAt } : {},
|
|
1489
|
+
remainingSeconds: secondsUntil5(resetsAt, now),
|
|
1490
|
+
state: "fresh"
|
|
1491
|
+
});
|
|
1492
|
+
}
|
|
1493
|
+
return windows.length > 0 ? windows : null;
|
|
841
1494
|
}
|
|
842
|
-
|
|
843
|
-
|
|
1495
|
+
function githubApiBase(tokens) {
|
|
1496
|
+
return (0, import_subscriptions6.copilotGitHubApiBase)(tokens.enterpriseUrl);
|
|
1497
|
+
}
|
|
1498
|
+
var CopilotAllowanceCollector = class {
|
|
1499
|
+
constructor(credentials, store = (0, import_AccountAllowanceStore5.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch5.fetchUpstream)(url, init, { providerId: "copilot", accountId, redactBodies: true }), now = Date.now) {
|
|
844
1500
|
this.credentials = credentials;
|
|
845
1501
|
this.store = store;
|
|
846
1502
|
this.fetchImpl = fetchImpl;
|
|
@@ -852,13 +1508,15 @@ var KimiAllowanceCollector = class {
|
|
|
852
1508
|
now;
|
|
853
1509
|
inFlight = /* @__PURE__ */ new Map();
|
|
854
1510
|
async collectMany(accounts, options = {}) {
|
|
855
|
-
const settled = await Promise.allSettled(
|
|
1511
|
+
const settled = await Promise.allSettled(
|
|
1512
|
+
accounts.map((account) => this.collect(account, options))
|
|
1513
|
+
);
|
|
856
1514
|
return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
|
|
857
1515
|
}
|
|
858
1516
|
collect(account, options = {}) {
|
|
859
1517
|
const now = this.now();
|
|
860
1518
|
if (account.tokens.authMethod !== "oauth") {
|
|
861
|
-
const existing = this.store.get("
|
|
1519
|
+
const existing = this.store.get("copilot", account.id, now);
|
|
862
1520
|
if (existing?.windows.every((window) => window.state === "unsupported")) {
|
|
863
1521
|
return Promise.resolve(existing);
|
|
864
1522
|
}
|
|
@@ -866,13 +1524,13 @@ var KimiAllowanceCollector = class {
|
|
|
866
1524
|
this.store.set(snapshot);
|
|
867
1525
|
return Promise.resolve(snapshot);
|
|
868
1526
|
}
|
|
869
|
-
const cached = this.store.get("
|
|
1527
|
+
const cached = this.store.get("copilot", account.id, now);
|
|
870
1528
|
if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) {
|
|
871
1529
|
return Promise.resolve(cached);
|
|
872
1530
|
}
|
|
873
1531
|
const running = this.inFlight.get(account.id);
|
|
874
1532
|
if (running) return running;
|
|
875
|
-
const promise = this.fetchAccount(account.id, account.tokens).catch(() => this.failureSnapshot(account.id, "
|
|
1533
|
+
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));
|
|
876
1534
|
this.inFlight.set(account.id, promise);
|
|
877
1535
|
return promise;
|
|
878
1536
|
}
|
|
@@ -883,100 +1541,96 @@ var KimiAllowanceCollector = class {
|
|
|
883
1541
|
return Number.isFinite(expiresAt) && expiresAt > now + ahead;
|
|
884
1542
|
}
|
|
885
1543
|
async fetchAccount(accountId, tokens) {
|
|
886
|
-
let accessToken = await this.credentials.getAccessTokenForAccount("
|
|
887
|
-
if (!accessToken) return this.failureSnapshot(accountId, "
|
|
1544
|
+
let accessToken = await this.credentials.getAccessTokenForAccount("copilot", accountId);
|
|
1545
|
+
if (!accessToken) return this.failureSnapshot(accountId, "copilot_usage_token_unavailable", this.now());
|
|
888
1546
|
let response = await this.request(accountId, accessToken, tokens);
|
|
889
|
-
if (response.status === 401) {
|
|
890
|
-
const refreshed = await this.credentials.refreshAccountToken("
|
|
891
|
-
if (!refreshed) return this.failureSnapshot(accountId, "
|
|
892
|
-
accessToken = await this.credentials.getAccessTokenForAccount("
|
|
893
|
-
if (!accessToken) return this.failureSnapshot(accountId, "
|
|
1547
|
+
if (response.status === 401 || response.status === 403) {
|
|
1548
|
+
const refreshed = await this.credentials.refreshAccountToken("copilot", accountId);
|
|
1549
|
+
if (!refreshed) return this.failureSnapshot(accountId, "copilot_usage_unauthorized", this.now());
|
|
1550
|
+
accessToken = await this.credentials.getAccessTokenForAccount("copilot", accountId);
|
|
1551
|
+
if (!accessToken) return this.failureSnapshot(accountId, "copilot_usage_token_unavailable", this.now());
|
|
894
1552
|
response = await this.request(accountId, accessToken, tokens);
|
|
1553
|
+
if (response.status === 401 || response.status === 403) {
|
|
1554
|
+
return this.failureSnapshot(accountId, "copilot_usage_unauthorized", this.now());
|
|
1555
|
+
}
|
|
895
1556
|
}
|
|
896
|
-
if (response.
|
|
897
|
-
const snapshot2 = this.unsupportedSnapshot(accountId, this.now(), "kimi_usage_unsupported");
|
|
898
|
-
this.store.set(snapshot2);
|
|
899
|
-
return snapshot2;
|
|
900
|
-
}
|
|
901
|
-
if (!response.ok) return this.failureSnapshot(accountId, "kimi_usage_http_error", this.now());
|
|
1557
|
+
if (!response.ok) return this.failureSnapshot(accountId, "copilot_usage_http_error", this.now());
|
|
902
1558
|
let payload;
|
|
903
1559
|
try {
|
|
904
1560
|
payload = await response.json();
|
|
905
1561
|
} catch {
|
|
906
|
-
return this.failureSnapshot(accountId, "
|
|
1562
|
+
return this.failureSnapshot(accountId, "copilot_usage_invalid_response", this.now());
|
|
907
1563
|
}
|
|
908
1564
|
const now = this.now();
|
|
909
|
-
const windows =
|
|
1565
|
+
const windows = parseCopilotUserPayload(payload, now);
|
|
910
1566
|
const snapshot = {
|
|
911
|
-
providerId: "
|
|
1567
|
+
providerId: "copilot",
|
|
912
1568
|
accountId,
|
|
913
1569
|
source: "oauth-usage-api",
|
|
914
1570
|
observedAt: new Date(now).toISOString(),
|
|
915
|
-
expiresAt: new Date(now +
|
|
916
|
-
windows: windows
|
|
917
|
-
{ id: "
|
|
918
|
-
{ id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" }
|
|
1571
|
+
expiresAt: new Date(now + COPILOT_ALLOWANCE_CACHE_MS).toISOString(),
|
|
1572
|
+
windows: windows ?? [
|
|
1573
|
+
{ id: "thirty-day", label: "Monthly", scope: "all", usedPercent: null, state: "unavailable" }
|
|
919
1574
|
],
|
|
920
|
-
...windows
|
|
1575
|
+
...windows ? {} : { lastErrorCode: "copilot_usage_invalid_response" }
|
|
921
1576
|
};
|
|
922
1577
|
this.store.set(snapshot);
|
|
923
1578
|
return snapshot;
|
|
924
1579
|
}
|
|
925
1580
|
request(accountId, accessToken, tokens) {
|
|
926
|
-
return this.fetchImpl(
|
|
1581
|
+
return this.fetchImpl(`${githubApiBase(tokens)}/copilot_internal/user`, {
|
|
927
1582
|
method: "GET",
|
|
928
1583
|
headers: {
|
|
929
1584
|
Authorization: `Bearer ${accessToken}`,
|
|
930
1585
|
Accept: "application/json",
|
|
931
|
-
|
|
1586
|
+
"Content-Type": "application/json",
|
|
1587
|
+
...import_subscriptions6.COPILOT_GITHUB_HEADERS
|
|
932
1588
|
},
|
|
933
1589
|
signal: AbortSignal.timeout(15e3)
|
|
934
1590
|
}, accountId);
|
|
935
1591
|
}
|
|
936
1592
|
failureSnapshot(accountId, code, now) {
|
|
937
|
-
const existing = this.store.get("
|
|
1593
|
+
const existing = this.store.get("copilot", accountId, now);
|
|
938
1594
|
const snapshot = existing ? {
|
|
939
1595
|
...existing,
|
|
940
|
-
expiresAt: new Date(now +
|
|
1596
|
+
expiresAt: new Date(now + COPILOT_ALLOWANCE_CACHE_MS).toISOString(),
|
|
941
1597
|
windows: existing.windows.map((window) => ({
|
|
942
1598
|
...window,
|
|
943
1599
|
state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt ? "stale" : "unavailable"
|
|
944
1600
|
})),
|
|
945
1601
|
lastErrorCode: code
|
|
946
1602
|
} : {
|
|
947
|
-
providerId: "
|
|
1603
|
+
providerId: "copilot",
|
|
948
1604
|
accountId,
|
|
949
1605
|
source: "oauth-usage-api",
|
|
950
1606
|
observedAt: new Date(now).toISOString(),
|
|
951
|
-
expiresAt: new Date(now +
|
|
1607
|
+
expiresAt: new Date(now + COPILOT_ALLOWANCE_CACHE_MS).toISOString(),
|
|
952
1608
|
windows: [
|
|
953
|
-
{ id: "
|
|
954
|
-
{ id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" }
|
|
1609
|
+
{ id: "thirty-day", label: "Monthly", scope: "all", usedPercent: null, state: "unavailable" }
|
|
955
1610
|
],
|
|
956
1611
|
lastErrorCode: code
|
|
957
1612
|
};
|
|
958
1613
|
this.store.set(snapshot);
|
|
959
1614
|
return snapshot;
|
|
960
1615
|
}
|
|
961
|
-
unsupportedSnapshot(accountId, now
|
|
1616
|
+
unsupportedSnapshot(accountId, now) {
|
|
962
1617
|
return {
|
|
963
|
-
providerId: "
|
|
1618
|
+
providerId: "copilot",
|
|
964
1619
|
accountId,
|
|
965
1620
|
source: "oauth-usage-api",
|
|
966
1621
|
observedAt: new Date(now).toISOString(),
|
|
967
1622
|
windows: [
|
|
968
|
-
{ id: "
|
|
969
|
-
{ id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unsupported" }
|
|
1623
|
+
{ id: "thirty-day", label: "Monthly", scope: "all", usedPercent: null, state: "unsupported" }
|
|
970
1624
|
],
|
|
971
|
-
lastErrorCode:
|
|
1625
|
+
lastErrorCode: "copilot_usage_unsupported_auth"
|
|
972
1626
|
};
|
|
973
1627
|
}
|
|
974
1628
|
};
|
|
975
1629
|
|
|
976
1630
|
// src/allowance/OpenCodeGoAllowanceCollector.ts
|
|
977
|
-
var
|
|
978
|
-
var
|
|
979
|
-
var
|
|
1631
|
+
var import_AccountAllowanceStore6 = require("@omnicross/core/pipeline/AccountAllowanceStore");
|
|
1632
|
+
var import_upstreamFetch6 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
1633
|
+
var import_subscriptions7 = require("@omnicross/subscriptions");
|
|
980
1634
|
var OPENCODEGO_ALLOWANCE_CACHE_MS = 5 * 6e4;
|
|
981
1635
|
var OPENCODEGO_DEFAULT_GO_BASE = "https://opencode.ai/zen/go";
|
|
982
1636
|
function finitePercent3(value) {
|
|
@@ -989,7 +1643,7 @@ function isoInstant2(value) {
|
|
|
989
1643
|
const time = Date.parse(value);
|
|
990
1644
|
return Number.isFinite(time) ? new Date(time).toISOString() : void 0;
|
|
991
1645
|
}
|
|
992
|
-
function
|
|
1646
|
+
function secondsUntil6(instant, now) {
|
|
993
1647
|
if (!instant) return void 0;
|
|
994
1648
|
return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
|
|
995
1649
|
}
|
|
@@ -1004,12 +1658,12 @@ function windowFromPayload3(id, label, minutes, payload, now) {
|
|
|
1004
1658
|
usedPercent,
|
|
1005
1659
|
windowMinutes: minutes,
|
|
1006
1660
|
...resetsAt !== void 0 ? { resetsAt } : {},
|
|
1007
|
-
remainingSeconds:
|
|
1661
|
+
remainingSeconds: secondsUntil6(resetsAt, now),
|
|
1008
1662
|
state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
|
|
1009
1663
|
};
|
|
1010
1664
|
}
|
|
1011
1665
|
var OpenCodeGoAllowanceCollector = class {
|
|
1012
|
-
constructor(credentials, store = (0,
|
|
1666
|
+
constructor(credentials, store = (0, import_AccountAllowanceStore6.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch6.fetchUpstream)(url, init, { providerId: "opencodego", accountId, redactBodies: true }), now = Date.now) {
|
|
1013
1667
|
this.credentials = credentials;
|
|
1014
1668
|
this.store = store;
|
|
1015
1669
|
this.fetchImpl = fetchImpl;
|
|
@@ -1039,7 +1693,7 @@ var OpenCodeGoAllowanceCollector = class {
|
|
|
1039
1693
|
async fetchAccount(account) {
|
|
1040
1694
|
const apiKey = await this.credentials.getAccessTokenForAccount("opencodego", account.id);
|
|
1041
1695
|
if (!apiKey) return this.failureSnapshot(account.id, this.now());
|
|
1042
|
-
const base = account.tokens.baseUrl ? (0,
|
|
1696
|
+
const base = account.tokens.baseUrl ? (0, import_subscriptions7.normalizeOpenCodeGoBaseUrl)(account.tokens.baseUrl) : OPENCODEGO_DEFAULT_GO_BASE;
|
|
1043
1697
|
const response = await this.fetchImpl(`${base}/v1/usage`, {
|
|
1044
1698
|
method: "GET",
|
|
1045
1699
|
headers: { Authorization: `Bearer ${apiKey}`, Accept: "application/json" },
|
|
@@ -1114,7 +1768,7 @@ function codexUnavailable(accountId, now) {
|
|
|
1114
1768
|
};
|
|
1115
1769
|
}
|
|
1116
1770
|
var AccountAllowanceService = class {
|
|
1117
|
-
constructor(credentials, store = (0,
|
|
1771
|
+
constructor(credentials, store = (0, import_AccountAllowanceStore7.getSharedAccountAllowanceStore)(), collector, codexCollector, kimiCollector, opencodegoCollector, grokCollector, copilotCollector, now = Date.now) {
|
|
1118
1772
|
this.credentials = credentials;
|
|
1119
1773
|
this.store = store;
|
|
1120
1774
|
this.now = now;
|
|
@@ -1122,6 +1776,8 @@ var AccountAllowanceService = class {
|
|
|
1122
1776
|
this.codexCollector = codexCollector ?? new CodexAllowanceCollector(credentials, store);
|
|
1123
1777
|
this.kimiCollector = kimiCollector ?? new KimiAllowanceCollector(credentials, store);
|
|
1124
1778
|
this.opencodegoCollector = opencodegoCollector ?? new OpenCodeGoAllowanceCollector(credentials, store);
|
|
1779
|
+
this.grokCollector = grokCollector ?? new GrokAllowanceCollector(credentials, store);
|
|
1780
|
+
this.copilotCollector = copilotCollector ?? new CopilotAllowanceCollector(credentials, store);
|
|
1125
1781
|
}
|
|
1126
1782
|
credentials;
|
|
1127
1783
|
store;
|
|
@@ -1129,6 +1785,8 @@ var AccountAllowanceService = class {
|
|
|
1129
1785
|
claudeCollector;
|
|
1130
1786
|
codexCollector;
|
|
1131
1787
|
kimiCollector;
|
|
1788
|
+
grokCollector;
|
|
1789
|
+
copilotCollector;
|
|
1132
1790
|
opencodegoCollector;
|
|
1133
1791
|
/**
|
|
1134
1792
|
* Read all/filtered snapshots. Claude's and Codex's five-minute caches are
|
|
@@ -1163,11 +1821,23 @@ var AccountAllowanceService = class {
|
|
|
1163
1821
|
(account) => !filter.accountId || account.id === filter.accountId
|
|
1164
1822
|
);
|
|
1165
1823
|
if (wantsOpenCodeGo) await this.opencodegoCollector.collectMany(opencodegoAccounts);
|
|
1824
|
+
const wantsGrok = !filter.providerId || filter.providerId === "grok";
|
|
1825
|
+
const grokAccounts = (config.grokAccounts ?? []).filter(
|
|
1826
|
+
(account) => !filter.accountId || account.id === filter.accountId
|
|
1827
|
+
);
|
|
1828
|
+
if (wantsGrok) await this.grokCollector.collectMany(grokAccounts);
|
|
1829
|
+
const wantsCopilot = !filter.providerId || filter.providerId === "copilot";
|
|
1830
|
+
const copilotAccounts = (config.copilotAccounts ?? []).filter(
|
|
1831
|
+
(account) => !filter.accountId || account.id === filter.accountId
|
|
1832
|
+
);
|
|
1833
|
+
if (wantsCopilot) await this.copilotCollector.collectMany(copilotAccounts);
|
|
1166
1834
|
const known = /* @__PURE__ */ new Set();
|
|
1167
1835
|
if (wantsClaude) for (const account of claudeAccounts) known.add(`claude\0${account.id}`);
|
|
1168
1836
|
if (wantsCodex) for (const account of codexAccounts) known.add(`codex\0${account.id}`);
|
|
1169
1837
|
if (wantsKimi) for (const account of kimiAccounts) known.add(`kimi\0${account.id}`);
|
|
1170
1838
|
if (wantsOpenCodeGo) for (const account of opencodegoAccounts) known.add(`opencodego\0${account.id}`);
|
|
1839
|
+
if (wantsGrok) for (const account of grokAccounts) known.add(`grok\0${account.id}`);
|
|
1840
|
+
if (wantsCopilot) for (const account of copilotAccounts) known.add(`copilot\0${account.id}`);
|
|
1171
1841
|
return this.store.list(filter).filter((snapshot) => known.has(`${snapshot.providerId}\0${snapshot.accountId}`));
|
|
1172
1842
|
}
|
|
1173
1843
|
knownAccounts(config) {
|
|
@@ -1175,7 +1845,9 @@ var AccountAllowanceService = class {
|
|
|
1175
1845
|
...(config.claudeAccounts ?? []).map((account) => ({ providerId: "claude", accountId: account.id })),
|
|
1176
1846
|
...(config.codexAccounts ?? []).map((account) => ({ providerId: "codex", accountId: account.id })),
|
|
1177
1847
|
...(config.kimiAccounts ?? []).map((account) => ({ providerId: "kimi", accountId: account.id })),
|
|
1178
|
-
...(config.opencodegoAccounts ?? []).map((account) => ({ providerId: "opencodego", accountId: account.id }))
|
|
1848
|
+
...(config.opencodegoAccounts ?? []).map((account) => ({ providerId: "opencodego", accountId: account.id })),
|
|
1849
|
+
...(config.grokAccounts ?? []).map((account) => ({ providerId: "grok", accountId: account.id })),
|
|
1850
|
+
...(config.copilotAccounts ?? []).map((account) => ({ providerId: "copilot", accountId: account.id }))
|
|
1179
1851
|
];
|
|
1180
1852
|
}
|
|
1181
1853
|
/** Force-refresh Claude usage for one account or every stored Claude account. */
|
|
@@ -1218,6 +1890,24 @@ var AccountAllowanceService = class {
|
|
|
1218
1890
|
);
|
|
1219
1891
|
return this.kimiCollector.collectMany(accounts, { force: true });
|
|
1220
1892
|
}
|
|
1893
|
+
/** Force-refresh Copilot usage (copilot_internal/user) for one/all accounts. */
|
|
1894
|
+
async refreshCopilot(accountId) {
|
|
1895
|
+
const config = await this.credentials.getFullConfig();
|
|
1896
|
+
this.store.pruneToKnownAccounts(this.knownAccounts(config));
|
|
1897
|
+
const accounts = (config.copilotAccounts ?? []).filter(
|
|
1898
|
+
(account) => !accountId || account.id === accountId
|
|
1899
|
+
);
|
|
1900
|
+
return this.copilotCollector.collectMany(accounts, { force: true });
|
|
1901
|
+
}
|
|
1902
|
+
/** Force-refresh Grok usage (CLI billing proxy) for one/all accounts. */
|
|
1903
|
+
async refreshGrok(accountId) {
|
|
1904
|
+
const config = await this.credentials.getFullConfig();
|
|
1905
|
+
this.store.pruneToKnownAccounts(this.knownAccounts(config));
|
|
1906
|
+
const accounts = (config.grokAccounts ?? []).filter(
|
|
1907
|
+
(account) => !accountId || account.id === accountId
|
|
1908
|
+
);
|
|
1909
|
+
return this.grokCollector.collectMany(accounts, { force: true });
|
|
1910
|
+
}
|
|
1221
1911
|
/**
|
|
1222
1912
|
* Keep Claude + Codex + Kimi snapshots warm for allowance-aware routing. All
|
|
1223
1913
|
* collectors preserve their cache + per-account in-flight coalescing; a tick
|
|
@@ -1232,6 +1922,8 @@ var AccountAllowanceService = class {
|
|
|
1232
1922
|
await this.codexCollector.collectMany(config.codexAccounts ?? [], { refreshAheadMs });
|
|
1233
1923
|
await this.kimiCollector.collectMany(config.kimiAccounts ?? [], { refreshAheadMs });
|
|
1234
1924
|
await this.opencodegoCollector.collectMany(config.opencodegoAccounts ?? [], { refreshAheadMs });
|
|
1925
|
+
await this.grokCollector.collectMany(config.grokAccounts ?? [], { refreshAheadMs });
|
|
1926
|
+
await this.copilotCollector.collectMany(config.copilotAccounts ?? [], { refreshAheadMs });
|
|
1235
1927
|
}
|
|
1236
1928
|
/** Remove a cache row as soon as an account is deleted by the admin path. */
|
|
1237
1929
|
removeAccountSnapshot(providerId, accountId) {
|
|
@@ -1326,7 +2018,7 @@ var ClaudeAllowanceRefreshScheduler = class {
|
|
|
1326
2018
|
var import_node_crypto2 = require("crypto");
|
|
1327
2019
|
var import_node_fs = require("fs");
|
|
1328
2020
|
var import_node_path = require("path");
|
|
1329
|
-
var
|
|
2021
|
+
var import_AccountAllowanceStore8 = require("@omnicross/core/pipeline/AccountAllowanceStore");
|
|
1330
2022
|
var ACCOUNT_ALLOWANCE_CACHE_VERSION = 1;
|
|
1331
2023
|
var MAX_PERSISTED_ALLOWANCE_SNAPSHOTS = 256;
|
|
1332
2024
|
var MAX_ALLOWANCE_CACHE_BYTES = 1e6;
|
|
@@ -1355,7 +2047,7 @@ var JsonAccountAllowancePersistence = class {
|
|
|
1355
2047
|
save(snapshots) {
|
|
1356
2048
|
const rows = [];
|
|
1357
2049
|
for (const snapshot of snapshots) {
|
|
1358
|
-
const normalized2 = (0,
|
|
2050
|
+
const normalized2 = (0, import_AccountAllowanceStore8.normalizeAccountAllowanceSnapshot)(snapshot);
|
|
1359
2051
|
if (!normalized2) continue;
|
|
1360
2052
|
rows.push(normalized2);
|
|
1361
2053
|
if (rows.length >= MAX_PERSISTED_ALLOWANCE_SNAPSHOTS) break;
|
|
@@ -1638,7 +2330,8 @@ var import_outbound_api5 = require("@omnicross/core/outbound-api");
|
|
|
1638
2330
|
var import_image_generation_types = require("@omnicross/contracts/image-generation-types");
|
|
1639
2331
|
var import_AccountAllowanceScheduling2 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
|
|
1640
2332
|
var import_SubscriptionAccountHealth = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
|
|
1641
|
-
var
|
|
2333
|
+
var import_upstreamFetch9 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
2334
|
+
var import_core3 = require("@omnicross/core");
|
|
1642
2335
|
|
|
1643
2336
|
// src/image-generation/imagesConfigValidation.ts
|
|
1644
2337
|
var import_outbound_api = require("@omnicross/core/outbound-api");
|
|
@@ -1934,6 +2627,7 @@ async function applyServerConfigTransaction(current, next, deps) {
|
|
|
1934
2627
|
|
|
1935
2628
|
// src/config.ts
|
|
1936
2629
|
var import_node_fs4 = require("fs");
|
|
2630
|
+
var import_core = require("@omnicross/core");
|
|
1937
2631
|
|
|
1938
2632
|
// src/secrets/envelope.ts
|
|
1939
2633
|
var import_node_crypto4 = require("crypto");
|
|
@@ -2345,6 +3039,18 @@ var FORMAT_AXIS_TRANSFORMERS = [
|
|
|
2345
3039
|
"openai-response",
|
|
2346
3040
|
"gemini-code-assist"
|
|
2347
3041
|
];
|
|
3042
|
+
function validateExtraHeaders(raw) {
|
|
3043
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
3044
|
+
const reserved = import_core.EXTRA_HEADER_RESERVED_NAMES;
|
|
3045
|
+
const out = {};
|
|
3046
|
+
for (const [name, value] of Object.entries(raw)) {
|
|
3047
|
+
if (!name.trim()) continue;
|
|
3048
|
+
if (typeof value !== "string") continue;
|
|
3049
|
+
if (reserved.has(name.toLowerCase())) continue;
|
|
3050
|
+
out[name] = value;
|
|
3051
|
+
}
|
|
3052
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
3053
|
+
}
|
|
2348
3054
|
function validateApiKeys(raw) {
|
|
2349
3055
|
if (!Array.isArray(raw)) return void 0;
|
|
2350
3056
|
const out = [];
|
|
@@ -2558,6 +3264,9 @@ function validateProvider(raw, index) {
|
|
|
2558
3264
|
apiVersion,
|
|
2559
3265
|
maxConcurrency,
|
|
2560
3266
|
modelsEndpoint,
|
|
3267
|
+
// Static extra headers: load-guard (reserved names dropped), collapse-to-
|
|
3268
|
+
// undefined; enforced by the outbound header funnel + admin probes.
|
|
3269
|
+
extraHeaders: validateExtraHeaders(p["extraHeaders"]),
|
|
2561
3270
|
// Provider transformer config (app-parity child 5): load-guard, collapse-to-
|
|
2562
3271
|
// undefined; non-secret; ENFORCED via resolveTransformerChain (parity-2 child 2).
|
|
2563
3272
|
// Format-axis entries are stripped by `migrateFormatAxis` — `use[]` is the
|
|
@@ -2627,7 +3336,7 @@ var import_node_crypto6 = require("crypto");
|
|
|
2627
3336
|
var import_node_fs6 = require("fs");
|
|
2628
3337
|
var import_node_os3 = require("os");
|
|
2629
3338
|
var import_node_path6 = require("path");
|
|
2630
|
-
var
|
|
3339
|
+
var import_core2 = require("@omnicross/core");
|
|
2631
3340
|
|
|
2632
3341
|
// src/integrations/codexAuthHelper.ts
|
|
2633
3342
|
var import_node_path4 = require("path");
|
|
@@ -3108,7 +3817,7 @@ var IntegrationManager = class {
|
|
|
3108
3817
|
if (!secret) {
|
|
3109
3818
|
throw new IntegrationConflictError("The selected access key cannot be revealed and cannot power a CLI integration.");
|
|
3110
3819
|
}
|
|
3111
|
-
const effective = [...(0,
|
|
3820
|
+
const effective = [...(0, import_core2.effectiveOutboundPermissions)(row.allowedEndpoints)];
|
|
3112
3821
|
const previousPermissions = row.allowedEndpoints === void 0 ? [...effective] : [...row.allowedEndpoints];
|
|
3113
3822
|
const nextPermissions = [...effective];
|
|
3114
3823
|
for (const required of REQUIRED_PERMISSIONS[client]) {
|
|
@@ -3206,7 +3915,7 @@ var IntegrationManager = class {
|
|
|
3206
3915
|
return { binding, row, secret, created: false };
|
|
3207
3916
|
}
|
|
3208
3917
|
async createManagedClientKey(client, state) {
|
|
3209
|
-
const created = await (0,
|
|
3918
|
+
const created = await (0, import_core2.createIntegrationKey)(
|
|
3210
3919
|
this.options.keyDb,
|
|
3211
3920
|
`Omnicross ${displayClient(client)} integration`,
|
|
3212
3921
|
[...REQUIRED_PERMISSIONS[client]]
|
|
@@ -3298,7 +4007,7 @@ var IntegrationManager = class {
|
|
|
3298
4007
|
const row = rows.find((candidate) => candidate.id === keyId);
|
|
3299
4008
|
if (!row) return { usable: false, message: "The bound access key no longer exists." };
|
|
3300
4009
|
const secret = legacy?.secret ?? await this.options.keyDb.outboundApiKeysReveal(keyId) ?? void 0;
|
|
3301
|
-
const allowedEndpoints = [...(0,
|
|
4010
|
+
const allowedEndpoints = [...(0, import_core2.effectiveOutboundPermissions)(row.allowedEndpoints)];
|
|
3302
4011
|
const status = {
|
|
3303
4012
|
id: row.id,
|
|
3304
4013
|
name: row.name,
|
|
@@ -3342,7 +4051,7 @@ var IntegrationManager = class {
|
|
|
3342
4051
|
}
|
|
3343
4052
|
};
|
|
3344
4053
|
function hasRequiredPermissions(row, client) {
|
|
3345
|
-
const allowed = (0,
|
|
4054
|
+
const allowed = (0, import_core2.effectiveOutboundPermissions)(row.allowedEndpoints);
|
|
3346
4055
|
return REQUIRED_PERMISSIONS[client].every((permission) => allowed.includes(permission));
|
|
3347
4056
|
}
|
|
3348
4057
|
function samePermissions(a, b) {
|
|
@@ -3516,7 +4225,8 @@ function listMappablePresets() {
|
|
|
3516
4225
|
description: preset.description,
|
|
3517
4226
|
features: preset.features,
|
|
3518
4227
|
website: preset.website,
|
|
3519
|
-
modelsEndpoint: preset.modelsEndpoint
|
|
4228
|
+
modelsEndpoint: preset.modelsEndpoint,
|
|
4229
|
+
extraHeaders: preset.extraHeaders
|
|
3520
4230
|
});
|
|
3521
4231
|
}
|
|
3522
4232
|
return { mappable, excluded };
|
|
@@ -3606,11 +4316,11 @@ function preserveOutboundProxySecrets(incoming, current) {
|
|
|
3606
4316
|
}
|
|
3607
4317
|
|
|
3608
4318
|
// src/proxy/upstreamProxyResolver.ts
|
|
3609
|
-
var
|
|
4319
|
+
var import_upstreamFetch7 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
3610
4320
|
var serverProxy;
|
|
3611
4321
|
function setServerProxyConfig(proxy) {
|
|
3612
4322
|
serverProxy = proxy;
|
|
3613
|
-
(0,
|
|
4323
|
+
(0, import_upstreamFetch7.bumpUpstreamProxyGeneration)();
|
|
3614
4324
|
}
|
|
3615
4325
|
function getServerProxyConfig() {
|
|
3616
4326
|
return serverProxy;
|
|
@@ -3678,7 +4388,7 @@ function createUpstreamProxyResolver(src = {}) {
|
|
|
3678
4388
|
}
|
|
3679
4389
|
|
|
3680
4390
|
// src/admin/accountsOAuth.ts
|
|
3681
|
-
var
|
|
4391
|
+
var import_subscriptions8 = require("@omnicross/subscriptions");
|
|
3682
4392
|
|
|
3683
4393
|
// src/admin/accountsWrite.ts
|
|
3684
4394
|
var VALID_PROVIDER_IDS = [
|
|
@@ -3686,7 +4396,9 @@ var VALID_PROVIDER_IDS = [
|
|
|
3686
4396
|
"codex",
|
|
3687
4397
|
"gemini",
|
|
3688
4398
|
"opencodego",
|
|
3689
|
-
"kimi"
|
|
4399
|
+
"kimi",
|
|
4400
|
+
"grok",
|
|
4401
|
+
"copilot"
|
|
3690
4402
|
];
|
|
3691
4403
|
function asSubscriptionProviderId(id) {
|
|
3692
4404
|
return VALID_PROVIDER_IDS.includes(id) ? id : null;
|
|
@@ -3834,6 +4546,40 @@ function validateKimi(body) {
|
|
|
3834
4546
|
copyOptional(out, body, ["accessToken", "refreshToken", "expiresAt", "accountId", "deviceId", "lastRefreshedAt", "errorMessage"]);
|
|
3835
4547
|
return out;
|
|
3836
4548
|
}
|
|
4549
|
+
function validateGrok(body) {
|
|
4550
|
+
const authMethod = str(body["authMethod"]);
|
|
4551
|
+
const status = str(body["status"]);
|
|
4552
|
+
if (!authMethod || !OAUTH_AUTH_METHODS.has(authMethod)) return null;
|
|
4553
|
+
if (!status || !TOKEN_STATUSES.has(status)) return null;
|
|
4554
|
+
const out = {
|
|
4555
|
+
authMethod,
|
|
4556
|
+
status
|
|
4557
|
+
};
|
|
4558
|
+
copyOptional(out, body, ["accessToken", "refreshToken", "expiresAt", "accountId", "lastRefreshedAt", "errorMessage"]);
|
|
4559
|
+
return out;
|
|
4560
|
+
}
|
|
4561
|
+
function validateCopilot(body) {
|
|
4562
|
+
const authMethod = str(body["authMethod"]);
|
|
4563
|
+
const status = str(body["status"]);
|
|
4564
|
+
if (!authMethod || !OAUTH_AUTH_METHODS.has(authMethod)) return null;
|
|
4565
|
+
if (!status || !TOKEN_STATUSES.has(status)) return null;
|
|
4566
|
+
const out = {
|
|
4567
|
+
authMethod,
|
|
4568
|
+
status
|
|
4569
|
+
};
|
|
4570
|
+
copyOptional(out, body, [
|
|
4571
|
+
"accessToken",
|
|
4572
|
+
"refreshToken",
|
|
4573
|
+
"expiresAt",
|
|
4574
|
+
"accountId",
|
|
4575
|
+
"email",
|
|
4576
|
+
"apiEndpoint",
|
|
4577
|
+
"enterpriseUrl",
|
|
4578
|
+
"lastRefreshedAt",
|
|
4579
|
+
"errorMessage"
|
|
4580
|
+
]);
|
|
4581
|
+
return out;
|
|
4582
|
+
}
|
|
3837
4583
|
function validateOpenCodeGo(body) {
|
|
3838
4584
|
const authMethod = str(body["authMethod"]);
|
|
3839
4585
|
const status = str(body["status"]);
|
|
@@ -3871,6 +4617,10 @@ function validateTokenBody(providerId, body) {
|
|
|
3871
4617
|
return validateOpenCodeGo(body);
|
|
3872
4618
|
case "kimi":
|
|
3873
4619
|
return validateKimi(body);
|
|
4620
|
+
case "grok":
|
|
4621
|
+
return validateGrok(body);
|
|
4622
|
+
case "copilot":
|
|
4623
|
+
return validateCopilot(body);
|
|
3874
4624
|
default:
|
|
3875
4625
|
return null;
|
|
3876
4626
|
}
|
|
@@ -3900,37 +4650,37 @@ async function statusEntryFor(reader, providerId) {
|
|
|
3900
4650
|
|
|
3901
4651
|
// src/admin/accountsOAuth.ts
|
|
3902
4652
|
var OAUTH_HTTP_PROVIDERS = /* @__PURE__ */ new Set(["claude", "gemini"]);
|
|
3903
|
-
function
|
|
4653
|
+
function err5(status, message) {
|
|
3904
4654
|
return { status, body: { error: { type: "admin_api_error", message } } };
|
|
3905
4655
|
}
|
|
3906
4656
|
function handleOAuthStart(providerId, deps) {
|
|
3907
4657
|
if (!OAUTH_HTTP_PROVIDERS.has(providerId)) {
|
|
3908
|
-
return
|
|
4658
|
+
return err5(400, `oauth not available for provider '${providerId}'`);
|
|
3909
4659
|
}
|
|
3910
|
-
const flow = providerId === "claude" ?
|
|
4660
|
+
const flow = providerId === "claude" ? import_subscriptions8.claudeOAuth : import_subscriptions8.geminiOAuth;
|
|
3911
4661
|
const { authUrl, codeVerifier, state } = flow.generateAuthParams();
|
|
3912
4662
|
const sessionId = deps.oauthSessions.put({ providerId, codeVerifier, state });
|
|
3913
4663
|
return { status: 200, body: { authUrl, sessionId } };
|
|
3914
4664
|
}
|
|
3915
4665
|
async function handleOAuthComplete(providerId, body, deps) {
|
|
3916
4666
|
if (!OAUTH_HTTP_PROVIDERS.has(providerId)) {
|
|
3917
|
-
return
|
|
4667
|
+
return err5(400, `oauth not available for provider '${providerId}'`);
|
|
3918
4668
|
}
|
|
3919
4669
|
const sessionId = typeof body["sessionId"] === "string" ? body["sessionId"] : "";
|
|
3920
4670
|
const rawCode = typeof body["code"] === "string" ? body["code"] : "";
|
|
3921
|
-
if (!sessionId) return
|
|
3922
|
-
if (!rawCode) return
|
|
4671
|
+
if (!sessionId) return err5(400, "oauth complete requires { sessionId }");
|
|
4672
|
+
if (!rawCode) return err5(400, "oauth complete requires { code }");
|
|
3923
4673
|
const session = deps.oauthSessions.peek(sessionId);
|
|
3924
|
-
if (!session) return
|
|
4674
|
+
if (!session) return err5(410, "oauth session is unknown, expired, or already used");
|
|
3925
4675
|
if (session.providerId !== providerId) {
|
|
3926
|
-
return
|
|
4676
|
+
return err5(400, `oauth session does not match provider '${providerId}'`);
|
|
3927
4677
|
}
|
|
3928
4678
|
let code = rawCode.trim();
|
|
3929
4679
|
if (providerId === "claude") {
|
|
3930
4680
|
const [splitCode, pastedState] = code.split("#");
|
|
3931
|
-
if (!splitCode) return
|
|
4681
|
+
if (!splitCode) return err5(400, "no authorization code was provided");
|
|
3932
4682
|
if (pastedState && pastedState !== session.state) {
|
|
3933
|
-
return
|
|
4683
|
+
return err5(400, "oauth state did not match (possible CSRF) \u2014 aborting");
|
|
3934
4684
|
}
|
|
3935
4685
|
code = splitCode;
|
|
3936
4686
|
}
|
|
@@ -3940,7 +4690,7 @@ async function handleOAuthComplete(providerId, body, deps) {
|
|
|
3940
4690
|
block = providerId === "claude" ? await exchangeClaude(code, session.codeVerifier, session.state, exchangeFetch) : await exchangeGemini(code, session.codeVerifier, exchangeFetch);
|
|
3941
4691
|
} catch (exchangeError) {
|
|
3942
4692
|
const reason = exchangeError instanceof Error ? exchangeError.message : "token exchange failed";
|
|
3943
|
-
return
|
|
4693
|
+
return err5(502, `oauth token exchange failed for '${providerId}': ${reason}`);
|
|
3944
4694
|
}
|
|
3945
4695
|
deps.oauthSessions.consume(sessionId);
|
|
3946
4696
|
const label = typeof body["label"] === "string" && body["label"].trim() ? body["label"].trim() : void 0;
|
|
@@ -3949,7 +4699,7 @@ async function handleOAuthComplete(providerId, body, deps) {
|
|
|
3949
4699
|
return { status: 200, body: status ? { account: status } : { ok: true } };
|
|
3950
4700
|
}
|
|
3951
4701
|
async function exchangeClaude(code, codeVerifier, state, exchangeFetch) {
|
|
3952
|
-
const result = await
|
|
4702
|
+
const result = await import_subscriptions8.claudeOAuth.exchangeCodeForTokens(
|
|
3953
4703
|
{ authorizationCode: code, codeVerifier, state },
|
|
3954
4704
|
exchangeFetch
|
|
3955
4705
|
);
|
|
@@ -3965,7 +4715,7 @@ async function exchangeClaude(code, codeVerifier, state, exchangeFetch) {
|
|
|
3965
4715
|
};
|
|
3966
4716
|
}
|
|
3967
4717
|
async function exchangeGemini(code, codeVerifier, exchangeFetch) {
|
|
3968
|
-
const result = await
|
|
4718
|
+
const result = await import_subscriptions8.geminiOAuth.exchangeCodeForTokens(code, codeVerifier, exchangeFetch);
|
|
3969
4719
|
const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
|
|
3970
4720
|
return {
|
|
3971
4721
|
authMethod: "oauth",
|
|
@@ -4270,8 +5020,8 @@ function errBody(message) {
|
|
|
4270
5020
|
return { error: { type: "admin_api_error", message } };
|
|
4271
5021
|
}
|
|
4272
5022
|
var defaultCommandRunner = (command) => new Promise((resolve10) => {
|
|
4273
|
-
(0, import_node_child_process.exec)(command, { timeout: 18e4 }, (
|
|
4274
|
-
if (
|
|
5023
|
+
(0, import_node_child_process.exec)(command, { timeout: 18e4 }, (err8, _stdout, stderr) => {
|
|
5024
|
+
if (err8) resolve10({ ok: false, error: stderr.trim() || err8.message });
|
|
4275
5025
|
else resolve10({ ok: true });
|
|
4276
5026
|
});
|
|
4277
5027
|
});
|
|
@@ -4317,8 +5067,8 @@ async function handleCliLaunch(cli, body, ctx) {
|
|
|
4317
5067
|
providerId: typeof body["providerId"] === "string" ? body["providerId"] : void 0,
|
|
4318
5068
|
model: typeof body["model"] === "string" ? body["model"] : void 0
|
|
4319
5069
|
});
|
|
4320
|
-
} catch (
|
|
4321
|
-
return { status: 400, body: errBody(
|
|
5070
|
+
} catch (err8) {
|
|
5071
|
+
return { status: 400, body: errBody(err8 instanceof Error ? err8.message : "no launch target") };
|
|
4322
5072
|
}
|
|
4323
5073
|
const id = (0, import_node_crypto7.randomUUID)();
|
|
4324
5074
|
let leaseId2;
|
|
@@ -4346,9 +5096,9 @@ async function handleCliLaunch(cli, body, ctx) {
|
|
|
4346
5096
|
} else {
|
|
4347
5097
|
launch = await buildLaunchEnv(cli, ctx.llmConfig, target);
|
|
4348
5098
|
}
|
|
4349
|
-
} catch (
|
|
4350
|
-
const status =
|
|
4351
|
-
return { status, body: errBody(
|
|
5099
|
+
} catch (err8) {
|
|
5100
|
+
const status = err8 instanceof import_provider_proxy2.RouteLeaseError ? err8.status : 400;
|
|
5101
|
+
return { status, body: errBody(err8 instanceof Error ? err8.message : "failed to build launch env") };
|
|
4352
5102
|
}
|
|
4353
5103
|
const cwd = typeof body["cwd"] === "string" && body["cwd"].trim() ? body["cwd"].trim() : void 0;
|
|
4354
5104
|
const opener = ctx.opener ?? defaultTerminalOpener;
|
|
@@ -4376,9 +5126,9 @@ async function handleCliLaunch(cli, body, ctx) {
|
|
|
4376
5126
|
onFailure: onSessionEnd
|
|
4377
5127
|
});
|
|
4378
5128
|
if (cleanup) openerCleanup = cleanup;
|
|
4379
|
-
} catch (
|
|
5129
|
+
} catch (err8) {
|
|
4380
5130
|
onSessionEnd();
|
|
4381
|
-
return { status: 500, body: errBody(
|
|
5131
|
+
return { status: 500, body: errBody(err8 instanceof Error ? err8.message : "failed to open terminal") };
|
|
4382
5132
|
}
|
|
4383
5133
|
if (ended) {
|
|
4384
5134
|
openerCleanup?.();
|
|
@@ -4619,7 +5369,7 @@ function classifySearchFailure(stage, code) {
|
|
|
4619
5369
|
}
|
|
4620
5370
|
|
|
4621
5371
|
// src/search/SearchAssembly.ts
|
|
4622
|
-
var
|
|
5372
|
+
var import_upstreamFetch8 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
4623
5373
|
var import_search = require("@omnicross/core/search");
|
|
4624
5374
|
var import_api2 = require("@omnicross/core/search/api");
|
|
4625
5375
|
var import_http2 = require("@omnicross/core/search/http");
|
|
@@ -4637,7 +5387,7 @@ function searchPolicyFrom(config) {
|
|
|
4637
5387
|
};
|
|
4638
5388
|
}
|
|
4639
5389
|
function resolveSearchUpstreamDispatcher(url) {
|
|
4640
|
-
return (0,
|
|
5390
|
+
return (0, import_upstreamFetch8.resolveUpstreamDispatcher)({ url });
|
|
4641
5391
|
}
|
|
4642
5392
|
var searchUpstreamProxyConfig = createUpstreamProxyResolver();
|
|
4643
5393
|
function resolveSearchUpstreamProxyConfig(url) {
|
|
@@ -4919,7 +5669,7 @@ async function handleSearchQuery(req, res, deps) {
|
|
|
4919
5669
|
// src/admin/searchAdminView.ts
|
|
4920
5670
|
var API_KEY_PROVIDERS = /* @__PURE__ */ new Set(["tavily", "jina", "zhipu", "z.ai"]);
|
|
4921
5671
|
var BASIC_AUTH_PROVIDERS = /* @__PURE__ */ new Set(["searxng"]);
|
|
4922
|
-
function
|
|
5672
|
+
function isRecord4(value) {
|
|
4923
5673
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
4924
5674
|
}
|
|
4925
5675
|
function redactSearchServerConfig(search) {
|
|
@@ -4969,13 +5719,13 @@ function resolveSecretField(entry, field, stored) {
|
|
|
4969
5719
|
else delete entry[field];
|
|
4970
5720
|
}
|
|
4971
5721
|
function preserveSearchSecrets(incoming, current) {
|
|
4972
|
-
if (!
|
|
5722
|
+
if (!isRecord4(incoming)) return incoming;
|
|
4973
5723
|
const section = { ...incoming };
|
|
4974
5724
|
const providersValue = section["providers"];
|
|
4975
|
-
if (!
|
|
5725
|
+
if (!isRecord4(providersValue)) return section;
|
|
4976
5726
|
const providers = {};
|
|
4977
5727
|
for (const [id, entryValue] of Object.entries(providersValue)) {
|
|
4978
|
-
if (!
|
|
5728
|
+
if (!isRecord4(entryValue)) {
|
|
4979
5729
|
providers[id] = entryValue;
|
|
4980
5730
|
continue;
|
|
4981
5731
|
}
|
|
@@ -5053,7 +5803,7 @@ function parseKeyPolicyBody(body) {
|
|
|
5053
5803
|
var ENDPOINTS = /* @__PURE__ */ new Set(["chat", "responses", "messages", "gemini"]);
|
|
5054
5804
|
var TARGET_KINDS = /* @__PURE__ */ new Set(["account", "account-group", "account-pool", "provider"]);
|
|
5055
5805
|
var FALLBACKS = /* @__PURE__ */ new Set(["next", "fail", "global"]);
|
|
5056
|
-
function
|
|
5806
|
+
function isRecord5(value) {
|
|
5057
5807
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
5058
5808
|
}
|
|
5059
5809
|
function nonBlank(value) {
|
|
@@ -5073,7 +5823,7 @@ function validateGatewayBindingsSegment(patch) {
|
|
|
5073
5823
|
const ids = /* @__PURE__ */ new Set();
|
|
5074
5824
|
raw.forEach((entry, index) => {
|
|
5075
5825
|
const path2 = `bindings[${index}]`;
|
|
5076
|
-
if (!
|
|
5826
|
+
if (!isRecord5(entry)) {
|
|
5077
5827
|
errors.push(`${path2} must be an object`);
|
|
5078
5828
|
return;
|
|
5079
5829
|
}
|
|
@@ -5102,12 +5852,12 @@ function validateGatewayBindingsSegment(patch) {
|
|
|
5102
5852
|
} else if (entry.modelMappings.length > 100) {
|
|
5103
5853
|
errors.push(`${path2}.modelMappings cannot contain more than 100 entries`);
|
|
5104
5854
|
} else if (entry.modelMappings.some(
|
|
5105
|
-
(mapping) => !
|
|
5855
|
+
(mapping) => !isRecord5(mapping) || !nonBlank(mapping.source) || !nonBlank(mapping.target)
|
|
5106
5856
|
)) {
|
|
5107
5857
|
errors.push(`${path2}.modelMappings must contain non-empty source and target strings`);
|
|
5108
5858
|
}
|
|
5109
5859
|
}
|
|
5110
|
-
if (!
|
|
5860
|
+
if (!isRecord5(entry.target) || !TARGET_KINDS.has(String(entry.target.kind))) {
|
|
5111
5861
|
errors.push(`${path2}.target is invalid`);
|
|
5112
5862
|
} else {
|
|
5113
5863
|
if (!nonBlank(entry.target.providerId)) errors.push(`${path2}.target.providerId is required`);
|
|
@@ -5122,7 +5872,7 @@ function validateGatewayBindingsSegment(patch) {
|
|
|
5122
5872
|
}
|
|
5123
5873
|
}
|
|
5124
5874
|
if (entry.modelMap !== void 0) {
|
|
5125
|
-
if (!
|
|
5875
|
+
if (!isRecord5(entry.modelMap) || Object.values(entry.modelMap).some((value) => typeof value !== "string")) {
|
|
5126
5876
|
errors.push(`${path2}.modelMap must contain string values`);
|
|
5127
5877
|
}
|
|
5128
5878
|
}
|
|
@@ -5421,7 +6171,9 @@ var PROVIDER_KEYS = {
|
|
|
5421
6171
|
accounts: "opencodegoAccounts",
|
|
5422
6172
|
active: "activeOpencodegoAccountId"
|
|
5423
6173
|
},
|
|
5424
|
-
kimi: { block: "kimi", accounts: "kimiAccounts", active: "activeKimiAccountId" }
|
|
6174
|
+
kimi: { block: "kimi", accounts: "kimiAccounts", active: "activeKimiAccountId" },
|
|
6175
|
+
grok: { block: "grok", accounts: "grokAccounts", active: "activeGrokAccountId" },
|
|
6176
|
+
copilot: { block: "copilot", accounts: "copilotAccounts", active: "activeCopilotAccountId" }
|
|
5425
6177
|
};
|
|
5426
6178
|
function clone(value) {
|
|
5427
6179
|
return JSON.parse(JSON.stringify(value));
|
|
@@ -5943,7 +6695,7 @@ async function applyImport(packString, passphrase, mode, deps, parseProviderInpu
|
|
|
5943
6695
|
}
|
|
5944
6696
|
|
|
5945
6697
|
// src/admin/adminMigration.ts
|
|
5946
|
-
function
|
|
6698
|
+
function err6(status, message) {
|
|
5947
6699
|
return { status, body: { error: { type: "admin_api_error", message } } };
|
|
5948
6700
|
}
|
|
5949
6701
|
async function handleExport(body, deps) {
|
|
@@ -5953,30 +6705,30 @@ async function handleExport(body, deps) {
|
|
|
5953
6705
|
return { status: 200, body: { pack, version: BUNDLE_VERSION } };
|
|
5954
6706
|
} catch (error) {
|
|
5955
6707
|
if (error instanceof WeakPassphraseError) {
|
|
5956
|
-
return
|
|
6708
|
+
return err6(400, error.message);
|
|
5957
6709
|
}
|
|
5958
|
-
return
|
|
6710
|
+
return err6(500, "failed to build the migration pack");
|
|
5959
6711
|
}
|
|
5960
6712
|
}
|
|
5961
6713
|
async function handleImport(body, deps) {
|
|
5962
6714
|
const blob = typeof body["blob"] === "string" ? body["blob"] : "";
|
|
5963
6715
|
const passphrase = typeof body["passphrase"] === "string" ? body["passphrase"] : "";
|
|
5964
6716
|
const mode = body["mode"] === "overwrite" ? "overwrite" : "merge";
|
|
5965
|
-
if (!blob) return
|
|
6717
|
+
if (!blob) return err6(400, "import requires { blob }");
|
|
5966
6718
|
try {
|
|
5967
6719
|
const counts = await applyImport(blob, passphrase, mode, deps, deps.parseProviderInput);
|
|
5968
6720
|
return { status: 200, body: counts };
|
|
5969
6721
|
} catch (error) {
|
|
5970
6722
|
if (error instanceof WeakPassphraseError) {
|
|
5971
|
-
return
|
|
6723
|
+
return err6(400, error.message);
|
|
5972
6724
|
}
|
|
5973
|
-
return
|
|
6725
|
+
return err6(400, error instanceof Error ? error.message : "import failed");
|
|
5974
6726
|
}
|
|
5975
6727
|
}
|
|
5976
6728
|
|
|
5977
6729
|
// src/admin/usagePricing.ts
|
|
5978
6730
|
var import_usage = require("@omnicross/core/usage");
|
|
5979
|
-
var
|
|
6731
|
+
var err7 = (status, message) => ({
|
|
5980
6732
|
status,
|
|
5981
6733
|
body: { error: { type: "admin_api_error", message } }
|
|
5982
6734
|
});
|
|
@@ -5989,7 +6741,7 @@ function parseRange(query2) {
|
|
|
5989
6741
|
const startTs = parseFiniteInt(query2.get("startTs"));
|
|
5990
6742
|
const endTs = parseFiniteInt(query2.get("endTs"));
|
|
5991
6743
|
if (startTs === null || endTs === null) {
|
|
5992
|
-
return
|
|
6744
|
+
return err7(400, "startTs and endTs are required finite-integer unix-millis query params");
|
|
5993
6745
|
}
|
|
5994
6746
|
return { startTs, endTs };
|
|
5995
6747
|
}
|
|
@@ -6014,14 +6766,14 @@ async function handleUsageGet(view, query2, deps) {
|
|
|
6014
6766
|
case "timeseries": {
|
|
6015
6767
|
const bucket = query2.get("bucket");
|
|
6016
6768
|
if (bucket !== "hour" && bucket !== "day" && bucket !== "month") {
|
|
6017
|
-
return
|
|
6769
|
+
return err7(400, "bucket must be one of 'hour', 'day', 'month'");
|
|
6018
6770
|
}
|
|
6019
6771
|
const now = Date.now();
|
|
6020
6772
|
const clamped = { startTs: range.startTs, endTs: Math.min(range.endTs, now) };
|
|
6021
6773
|
if (clamped.startTs < clamped.endTs) {
|
|
6022
6774
|
const projected = Math.ceil((clamped.endTs - clamped.startTs) / BUCKET_SPAN_MS[bucket]) + 1;
|
|
6023
6775
|
if (projected > MAX_TIMESERIES_BUCKETS) {
|
|
6024
|
-
return
|
|
6776
|
+
return err7(
|
|
6025
6777
|
400,
|
|
6026
6778
|
`requested range projects ~${projected} '${bucket}' buckets (max ${MAX_TIMESERIES_BUCKETS}); narrow the range or use a coarser bucket`
|
|
6027
6779
|
);
|
|
@@ -6044,7 +6796,7 @@ async function handleUsageGet(view, query2, deps) {
|
|
|
6044
6796
|
};
|
|
6045
6797
|
}
|
|
6046
6798
|
default:
|
|
6047
|
-
return
|
|
6799
|
+
return err7(404, `unknown usage view '${view ?? ""}'`);
|
|
6048
6800
|
}
|
|
6049
6801
|
}
|
|
6050
6802
|
function poolKeyLabels(cfg) {
|
|
@@ -6093,7 +6845,7 @@ async function handlePricingList(deps) {
|
|
|
6093
6845
|
async function handlePricingUpsert(body, deps) {
|
|
6094
6846
|
const input = parsePricingEntryInput(body);
|
|
6095
6847
|
if (!input) {
|
|
6096
|
-
return
|
|
6848
|
+
return err7(400, "invalid pricing entry (providerId, modelId, finite numeric inputPricePer1m/outputPricePer1m required)");
|
|
6097
6849
|
}
|
|
6098
6850
|
const entry = await deps.pricingEngine.upsertManual(input);
|
|
6099
6851
|
return { status: 200, body: { entry } };
|
|
@@ -6102,7 +6854,7 @@ async function handlePricingDelete(query2, deps) {
|
|
|
6102
6854
|
const providerId = query2.get("providerId")?.trim() ?? "";
|
|
6103
6855
|
const modelId = query2.get("modelId")?.trim() ?? "";
|
|
6104
6856
|
if (!providerId || !modelId) {
|
|
6105
|
-
return
|
|
6857
|
+
return err7(400, "delete requires providerId and modelId query params");
|
|
6106
6858
|
}
|
|
6107
6859
|
const deleted = await deps.pricingStore.delete(providerId, modelId);
|
|
6108
6860
|
if (deleted) await deps.pricingEngine.invalidateCache();
|
|
@@ -6122,13 +6874,13 @@ async function handlePricingFetchLatest(deps) {
|
|
|
6122
6874
|
}
|
|
6123
6875
|
};
|
|
6124
6876
|
} catch (e) {
|
|
6125
|
-
return
|
|
6877
|
+
return err7(502, `pricing-source fetch failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
6126
6878
|
}
|
|
6127
6879
|
}
|
|
6128
6880
|
async function handlePricingResolveConflicts(body, deps) {
|
|
6129
6881
|
const raw = body["resolutions"];
|
|
6130
6882
|
if (!Array.isArray(raw)) {
|
|
6131
|
-
return
|
|
6883
|
+
return err7(400, "resolve-conflicts requires { resolutions: [...] }");
|
|
6132
6884
|
}
|
|
6133
6885
|
const currentRows = await deps.pricingStore.getAll();
|
|
6134
6886
|
const userEditedKeys = new Set(
|
|
@@ -6138,21 +6890,21 @@ async function handlePricingResolveConflicts(body, deps) {
|
|
|
6138
6890
|
const pendingIncoming = /* @__PURE__ */ new Map();
|
|
6139
6891
|
let staleCount = 0;
|
|
6140
6892
|
for (const item of raw) {
|
|
6141
|
-
if (!item || typeof item !== "object") return
|
|
6893
|
+
if (!item || typeof item !== "object") return err7(400, "invalid resolution entry");
|
|
6142
6894
|
const r = item;
|
|
6143
6895
|
const action = r["action"];
|
|
6144
6896
|
if (action !== "overwrite" && action !== "skip") {
|
|
6145
|
-
return
|
|
6897
|
+
return err7(400, "resolution action must be 'overwrite' or 'skip'");
|
|
6146
6898
|
}
|
|
6147
6899
|
const providerId = typeof r["providerId"] === "string" && r["providerId"].trim() ? r["providerId"].trim() : "";
|
|
6148
6900
|
const modelId = typeof r["modelId"] === "string" && r["modelId"].trim() ? r["modelId"].trim() : "";
|
|
6149
6901
|
if (!providerId || !modelId) {
|
|
6150
|
-
return
|
|
6902
|
+
return err7(400, "each resolution requires top-level providerId and modelId");
|
|
6151
6903
|
}
|
|
6152
6904
|
const incoming = parsePricingEntryInput(r["incoming"]);
|
|
6153
|
-
if (!incoming) return
|
|
6905
|
+
if (!incoming) return err7(400, "each resolution must echo a valid incoming pricing entry");
|
|
6154
6906
|
if (incoming.providerId !== providerId || incoming.modelId !== modelId) {
|
|
6155
|
-
return
|
|
6907
|
+
return err7(400, "resolution providerId/modelId must match the echoed incoming entry");
|
|
6156
6908
|
}
|
|
6157
6909
|
const key = `${providerId}::${modelId}`;
|
|
6158
6910
|
if (action === "overwrite" && !userEditedKeys.has(key)) {
|
|
@@ -6197,7 +6949,7 @@ function query(req) {
|
|
|
6197
6949
|
}
|
|
6198
6950
|
function allowanceProvider(value) {
|
|
6199
6951
|
if (!value) return void 0;
|
|
6200
|
-
return value === "claude" || value === "codex" || value === "kimi" || value === "opencodego" ? value : null;
|
|
6952
|
+
return value === "claude" || value === "codex" || value === "kimi" || value === "opencodego" || value === "grok" || value === "copilot" ? value : null;
|
|
6201
6953
|
}
|
|
6202
6954
|
async function handleAccountAllowanceApi(req, res, method, rest, service) {
|
|
6203
6955
|
if (!service) return writeError2(res, 501, "account allowance service is not available");
|
|
@@ -6212,7 +6964,7 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
|
|
|
6212
6964
|
const pathProvider = rest.length >= 2 ? rest[0] : null;
|
|
6213
6965
|
const providerId = allowanceProvider(pathProvider ?? params.get("providerId") ?? params.get("provider"));
|
|
6214
6966
|
if (providerId === null) {
|
|
6215
|
-
return writeError2(res, 400, "providerId must be claude, codex, kimi, or
|
|
6967
|
+
return writeError2(res, 400, "providerId must be claude, codex, kimi, opencodego, grok, or copilot");
|
|
6216
6968
|
}
|
|
6217
6969
|
const accountId = rest.length >= 2 ? rest[1] : params.get("accountId") ?? void 0;
|
|
6218
6970
|
const allowances = await service.list({ providerId, accountId });
|
|
@@ -6254,6 +7006,26 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
|
|
|
6254
7006
|
}
|
|
6255
7007
|
return writeJson3(res, 200, { allowances: allowances2 });
|
|
6256
7008
|
}
|
|
7009
|
+
if (requestedProvider === "copilot") {
|
|
7010
|
+
if (!service.refreshCopilot) {
|
|
7011
|
+
return writeError2(res, 501, "copilot allowance refresh is not available");
|
|
7012
|
+
}
|
|
7013
|
+
const allowances2 = await service.refreshCopilot(accountId);
|
|
7014
|
+
if (accountId && allowances2.length === 0) {
|
|
7015
|
+
return writeError2(res, 404, `Copilot account '${accountId}' not found`);
|
|
7016
|
+
}
|
|
7017
|
+
return writeJson3(res, 200, { allowances: allowances2 });
|
|
7018
|
+
}
|
|
7019
|
+
if (requestedProvider === "grok") {
|
|
7020
|
+
if (!service.refreshGrok) {
|
|
7021
|
+
return writeError2(res, 501, "grok allowance refresh is not available");
|
|
7022
|
+
}
|
|
7023
|
+
const allowances2 = await service.refreshGrok(accountId);
|
|
7024
|
+
if (accountId && allowances2.length === 0) {
|
|
7025
|
+
return writeError2(res, 404, `Grok account '${accountId}' not found`);
|
|
7026
|
+
}
|
|
7027
|
+
return writeJson3(res, 200, { allowances: allowances2 });
|
|
7028
|
+
}
|
|
6257
7029
|
const allowances = await service.refreshClaude(accountId);
|
|
6258
7030
|
if (accountId && allowances.length === 0) {
|
|
6259
7031
|
return writeError2(res, 404, `Claude account '${accountId}' not found`);
|
|
@@ -6352,6 +7124,9 @@ function toProviderView(row) {
|
|
|
6352
7124
|
apiVersion: row.apiVersion,
|
|
6353
7125
|
maxConcurrency: row.maxConcurrency,
|
|
6354
7126
|
modelsEndpoint: row.modelsEndpoint,
|
|
7127
|
+
// Static extra headers round-trip VERBATIM (non-secret identity values;
|
|
7128
|
+
// auth/content names were already dropped at the write/load gate).
|
|
7129
|
+
extraHeaders: row.extraHeaders,
|
|
6355
7130
|
// app-parity child 5: transformer config round-trips VERBATIM (non-secret —
|
|
6356
7131
|
// transform-rule names + options, no key material; absent stays absent).
|
|
6357
7132
|
transformer: row.transformer,
|
|
@@ -6421,8 +7196,8 @@ async function handleAdminApi(req, res, path2, deps) {
|
|
|
6421
7196
|
default:
|
|
6422
7197
|
return writeJsonError(res, 404, `unknown admin resource '${resource}'`);
|
|
6423
7198
|
}
|
|
6424
|
-
} catch (
|
|
6425
|
-
writeJsonError(res, 500,
|
|
7199
|
+
} catch (err8) {
|
|
7200
|
+
writeJsonError(res, 500, err8 instanceof Error ? err8.message : String(err8));
|
|
6426
7201
|
}
|
|
6427
7202
|
}
|
|
6428
7203
|
function requestQuery(req) {
|
|
@@ -6580,6 +7355,9 @@ async function handleProviderReorder(req, res, cfg, deps) {
|
|
|
6580
7355
|
persistProviders(cfg, deps);
|
|
6581
7356
|
return writeJson4(res, 200, { ok: true, providers: cfg.providers.map(toProviderView) });
|
|
6582
7357
|
}
|
|
7358
|
+
function expandRowExtraHeaders(row) {
|
|
7359
|
+
return (0, import_core3.mergeExtraHeaders)({}, row.extraHeaders);
|
|
7360
|
+
}
|
|
6583
7361
|
async function handleDiscoverModels(res, id, cfg) {
|
|
6584
7362
|
if (!id) return writeJsonError(res, 400, "provider id required in path");
|
|
6585
7363
|
const row = cfg.providers.find((p) => p.id === id);
|
|
@@ -6593,7 +7371,8 @@ async function handleDiscoverModels(res, id, cfg) {
|
|
|
6593
7371
|
try {
|
|
6594
7372
|
const headers = { Accept: "application/json" };
|
|
6595
7373
|
if (resolvedKey) headers["Authorization"] = `Bearer ${resolvedKey}`;
|
|
6596
|
-
|
|
7374
|
+
Object.assign(headers, expandRowExtraHeaders(row));
|
|
7375
|
+
const response = await (0, import_upstreamFetch9.fetchUpstream)(url, { method: "GET", headers }, { providerId: "byo" });
|
|
6597
7376
|
if (!response.ok) {
|
|
6598
7377
|
const text = await response.text().catch(() => "");
|
|
6599
7378
|
let message = text.slice(0, 300);
|
|
@@ -6610,8 +7389,8 @@ async function handleDiscoverModels(res, id, cfg) {
|
|
|
6610
7389
|
const data = await response.json();
|
|
6611
7390
|
const models = Array.isArray(data?.data) ? data.data.map((m) => typeof m?.id === "string" ? m.id : "").filter((m) => m.length > 0) : [];
|
|
6612
7391
|
return writeJson4(res, 200, { models });
|
|
6613
|
-
} catch (
|
|
6614
|
-
const message =
|
|
7392
|
+
} catch (err8) {
|
|
7393
|
+
const message = err8 instanceof Error ? err8.message : String(err8);
|
|
6615
7394
|
return writeJson4(res, 200, { models: [], error: `discovery failed: ${message}` });
|
|
6616
7395
|
}
|
|
6617
7396
|
}
|
|
@@ -6650,9 +7429,10 @@ async function handleTestModel(req, res, id, cfg) {
|
|
|
6650
7429
|
messages: [{ role: "user", content: prompt }]
|
|
6651
7430
|
};
|
|
6652
7431
|
}
|
|
7432
|
+
Object.assign(headers, expandRowExtraHeaders(row));
|
|
6653
7433
|
const startedAt = Date.now();
|
|
6654
7434
|
try {
|
|
6655
|
-
const response = await (0,
|
|
7435
|
+
const response = await (0, import_upstreamFetch9.fetchUpstream)(
|
|
6656
7436
|
url,
|
|
6657
7437
|
{ method: "POST", headers, body: JSON.stringify(payload) },
|
|
6658
7438
|
{ providerId: "byo" }
|
|
@@ -6674,8 +7454,8 @@ async function handleTestModel(req, res, id, cfg) {
|
|
|
6674
7454
|
latencyMs,
|
|
6675
7455
|
sample: extractSampleText(text, row.apiFormat)
|
|
6676
7456
|
});
|
|
6677
|
-
} catch (
|
|
6678
|
-
const message =
|
|
7457
|
+
} catch (err8) {
|
|
7458
|
+
const message = err8 instanceof Error ? err8.message : String(err8);
|
|
6679
7459
|
return writeJson4(res, 200, { ok: false, latencyMs: Date.now() - startedAt, message });
|
|
6680
7460
|
}
|
|
6681
7461
|
}
|
|
@@ -6957,6 +7737,7 @@ function parseProviderInput(body, existing) {
|
|
|
6957
7737
|
const apiVersion = typeof body["apiVersion"] === "string" && body["apiVersion"].length > 0 ? body["apiVersion"] : body["apiVersion"] === null ? void 0 : existing?.apiVersion;
|
|
6958
7738
|
const modelsEndpoint = typeof body["modelsEndpoint"] === "string" && body["modelsEndpoint"].length > 0 ? body["modelsEndpoint"] : body["modelsEndpoint"] === null ? void 0 : existing?.modelsEndpoint;
|
|
6959
7739
|
const maxConcurrency = typeof body["maxConcurrency"] === "number" && Number.isFinite(body["maxConcurrency"]) ? body["maxConcurrency"] : body["maxConcurrency"] === null ? void 0 : existing?.maxConcurrency;
|
|
7740
|
+
const extraHeaders = body["extraHeaders"] === null ? void 0 : body["extraHeaders"] === void 0 ? existing?.extraHeaders : validateExtraHeaders(body["extraHeaders"]);
|
|
6960
7741
|
const transformer = body["transformer"] === null ? void 0 : parseTransformerInput(body["transformer"], existing?.transformer);
|
|
6961
7742
|
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;
|
|
6962
7743
|
const apiModes = body["apiModes"] === null ? void 0 : parseApiModesInput(body["apiModes"], existing?.apiModes);
|
|
@@ -6982,6 +7763,7 @@ function parseProviderInput(body, existing) {
|
|
|
6982
7763
|
apiVersion,
|
|
6983
7764
|
maxConcurrency,
|
|
6984
7765
|
modelsEndpoint,
|
|
7766
|
+
extraHeaders,
|
|
6985
7767
|
transformer: migrated.transformer,
|
|
6986
7768
|
codingPlan,
|
|
6987
7769
|
apiModes,
|
|
@@ -7003,7 +7785,10 @@ function handlePresets(res, method) {
|
|
|
7003
7785
|
description: p.description,
|
|
7004
7786
|
features: p.features,
|
|
7005
7787
|
website: p.website,
|
|
7006
|
-
modelsEndpoint: p.modelsEndpoint
|
|
7788
|
+
modelsEndpoint: p.modelsEndpoint,
|
|
7789
|
+
// Static extra headers ride along so `addFromPreset` can seed them onto the
|
|
7790
|
+
// row (the write gateway re-validates via the shared allowlist).
|
|
7791
|
+
extraHeaders: p.extraHeaders
|
|
7007
7792
|
}));
|
|
7008
7793
|
return writeJson4(res, 200, { presets, excluded });
|
|
7009
7794
|
}
|
|
@@ -7485,12 +8270,12 @@ async function handleAccounts(req, res, method, rest, deps) {
|
|
|
7485
8270
|
}
|
|
7486
8271
|
return writeJson4(res, 200, { ok: true, affected: result.affected });
|
|
7487
8272
|
}
|
|
7488
|
-
if (method === "GET" && (rest[0] === "codex" || rest[0] === "kimi") && rest[1] === "oauth" && rest[3] === "status") {
|
|
7489
|
-
const result = rest[0] === "codex" ? handleCodexOAuthStatus(rest[2], deps) : handleKimiOAuthStatus(rest[2], deps);
|
|
8273
|
+
if (method === "GET" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot") && rest[1] === "oauth" && rest[3] === "status") {
|
|
8274
|
+
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);
|
|
7490
8275
|
return writeJson4(res, result.status, result.body);
|
|
7491
8276
|
}
|
|
7492
|
-
if (method === "DELETE" && (rest[0] === "codex" || rest[0] === "kimi") && rest[1] === "oauth" && rest[2]) {
|
|
7493
|
-
const result = rest[0] === "codex" ? handleCodexOAuthCancel(rest[2], deps) : handleKimiOAuthCancel(rest[2], deps);
|
|
8277
|
+
if (method === "DELETE" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot") && rest[1] === "oauth" && rest[2]) {
|
|
8278
|
+
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);
|
|
7494
8279
|
return writeJson4(res, result.status, result.body);
|
|
7495
8280
|
}
|
|
7496
8281
|
if (method === "GET" && rest.length === 3 && rest[2] === "diagnostics") {
|
|
@@ -7551,6 +8336,15 @@ async function handleAccounts(req, res, method, rest, deps) {
|
|
|
7551
8336
|
const result2 = await handleKimiOAuthStart(deps);
|
|
7552
8337
|
return writeJson4(res, result2.status, result2.body);
|
|
7553
8338
|
}
|
|
8339
|
+
if (providerId === "grok") {
|
|
8340
|
+
const result2 = await handleGrokOAuthStart(deps);
|
|
8341
|
+
return writeJson4(res, result2.status, result2.body);
|
|
8342
|
+
}
|
|
8343
|
+
if (providerId === "copilot") {
|
|
8344
|
+
const body2 = await readJsonBody4(req);
|
|
8345
|
+
const result2 = await handleCopilotOAuthStart(deps, body2["enterpriseUrl"]);
|
|
8346
|
+
return writeJson4(res, result2.status, result2.body);
|
|
8347
|
+
}
|
|
7554
8348
|
const result = handleOAuthStart(providerId, deps);
|
|
7555
8349
|
return writeJson4(res, result.status, result.body);
|
|
7556
8350
|
}
|
|
@@ -8045,12 +8839,12 @@ async function handlePlayground(req, res, method, deps) {
|
|
|
8045
8839
|
const payload = body["body"];
|
|
8046
8840
|
const status = deps.outboundApiServer.getStatus();
|
|
8047
8841
|
if (!status.running || !status.port) return writeJsonError(res, 503, "outbound server not running");
|
|
8048
|
-
const path2 = resolvePlaygroundPath(endpoint,
|
|
8842
|
+
const path2 = resolvePlaygroundPath(endpoint, isRecord6(payload) ? payload : {});
|
|
8049
8843
|
if (!path2) return writeJsonError(res, 400, `unknown endpoint '${endpoint}'`);
|
|
8050
8844
|
const upstreamBody = typeof payload === "string" ? payload : JSON.stringify(payload ?? {});
|
|
8051
8845
|
await proxyToOutbound(res, status.port, path2, key, upstreamBody);
|
|
8052
8846
|
}
|
|
8053
|
-
function
|
|
8847
|
+
function isRecord6(v) {
|
|
8054
8848
|
return !!v && typeof v === "object" && !Array.isArray(v);
|
|
8055
8849
|
}
|
|
8056
8850
|
function proxyToOutbound(res, outboundPort, path2, key, body) {
|
|
@@ -8079,8 +8873,8 @@ function proxyToOutbound(res, outboundPort, path2, key, body) {
|
|
|
8079
8873
|
});
|
|
8080
8874
|
}
|
|
8081
8875
|
);
|
|
8082
|
-
upstream.on("error", (
|
|
8083
|
-
if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${
|
|
8876
|
+
upstream.on("error", (err8) => {
|
|
8877
|
+
if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${err8.message}`);
|
|
8084
8878
|
else res.end();
|
|
8085
8879
|
resolve10();
|
|
8086
8880
|
});
|
|
@@ -8186,7 +8980,7 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
|
|
|
8186
8980
|
}
|
|
8187
8981
|
|
|
8188
8982
|
// src/admin/version.ts
|
|
8189
|
-
var DAEMON_VERSION = true ? "0.
|
|
8983
|
+
var DAEMON_VERSION = true ? "0.4.0" : "0.0.0-dev";
|
|
8190
8984
|
|
|
8191
8985
|
// src/admin/AdminServer.ts
|
|
8192
8986
|
var LOOPBACK_ADDR = "127.0.0.1";
|
|
@@ -8229,13 +9023,13 @@ var AdminServer = class {
|
|
|
8229
9023
|
const server = import_node_http2.default.createServer((req, res) => {
|
|
8230
9024
|
this.onRequest(req, res);
|
|
8231
9025
|
});
|
|
8232
|
-
const onError = (
|
|
8233
|
-
if (
|
|
9026
|
+
const onError = (err8) => {
|
|
9027
|
+
if (err8.code === "EADDRINUSE" && port !== 0) {
|
|
8234
9028
|
server.removeListener("error", onError);
|
|
8235
9029
|
this.listen(bindAddr, 0).then(resolve10, reject);
|
|
8236
9030
|
return;
|
|
8237
9031
|
}
|
|
8238
|
-
reject(
|
|
9032
|
+
reject(err8);
|
|
8239
9033
|
};
|
|
8240
9034
|
server.on("error", onError);
|
|
8241
9035
|
server.listen(port, bindAddr, () => {
|
|
@@ -8253,8 +9047,8 @@ var AdminServer = class {
|
|
|
8253
9047
|
}
|
|
8254
9048
|
/** Per-request handler: auth gate (when a token is set) → routing. */
|
|
8255
9049
|
onRequest(req, res) {
|
|
8256
|
-
void this.dispatch(req, res).catch((
|
|
8257
|
-
const message =
|
|
9050
|
+
void this.dispatch(req, res).catch((err8) => {
|
|
9051
|
+
const message = err8 instanceof Error ? err8.message : String(err8);
|
|
8258
9052
|
this.deps.logger.error("[AdminServer] unhandled error:", message);
|
|
8259
9053
|
if (!res.headersSent) {
|
|
8260
9054
|
res.writeHead(500, { "Content-Type": "application/json" });
|
|
@@ -8518,18 +9312,18 @@ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal
|
|
|
8518
9312
|
return;
|
|
8519
9313
|
}
|
|
8520
9314
|
signal?.addEventListener("abort", abort, { once: true });
|
|
8521
|
-
server.on("error", (
|
|
9315
|
+
server.on("error", (err8) => {
|
|
8522
9316
|
if (settled) return;
|
|
8523
9317
|
settled = true;
|
|
8524
9318
|
clearTimeout(timer);
|
|
8525
|
-
if (
|
|
9319
|
+
if (err8.code === "EADDRINUSE") {
|
|
8526
9320
|
reject(
|
|
8527
9321
|
new Error(
|
|
8528
9322
|
`login: cannot bind ${LOOPBACK_HOST}:${LOOPBACK_PORT} (address in use) \u2014 another codex login or process is holding the port`
|
|
8529
9323
|
)
|
|
8530
9324
|
);
|
|
8531
9325
|
} else {
|
|
8532
|
-
reject(
|
|
9326
|
+
reject(err8);
|
|
8533
9327
|
}
|
|
8534
9328
|
});
|
|
8535
9329
|
const timer = setTimeout(() => {
|
|
@@ -8605,21 +9399,22 @@ function createPoolKeysLoader(getProviderRow, autoDisabled) {
|
|
|
8605
9399
|
}
|
|
8606
9400
|
|
|
8607
9401
|
// src/allowance/ProviderKeyQuotaService.ts
|
|
8608
|
-
var
|
|
9402
|
+
var import_core4 = require("@omnicross/core");
|
|
9403
|
+
var import_upstreamFetch10 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
8609
9404
|
|
|
8610
9405
|
// src/allowance/ProviderKeyQuota.ts
|
|
8611
|
-
var
|
|
8612
|
-
var HOUR_MS2 = 60 *
|
|
8613
|
-
var
|
|
8614
|
-
var WEEK_MS = 7 *
|
|
8615
|
-
var MONTH_MS = 30 *
|
|
8616
|
-
function
|
|
9406
|
+
var MINUTE_MS3 = 6e4;
|
|
9407
|
+
var HOUR_MS2 = 60 * MINUTE_MS3;
|
|
9408
|
+
var DAY_MS3 = 24 * HOUR_MS2;
|
|
9409
|
+
var WEEK_MS = 7 * DAY_MS3;
|
|
9410
|
+
var MONTH_MS = 30 * DAY_MS3;
|
|
9411
|
+
function finiteNumber5(value) {
|
|
8617
9412
|
if (value === null || value === void 0 || value === "") return void 0;
|
|
8618
9413
|
const parsed = typeof value === "number" ? value : Number(value);
|
|
8619
9414
|
return Number.isFinite(parsed) && parsed >= 0 ? parsed : void 0;
|
|
8620
9415
|
}
|
|
8621
9416
|
function finitePercent4(value) {
|
|
8622
|
-
const parsed =
|
|
9417
|
+
const parsed = finiteNumber5(value);
|
|
8623
9418
|
return parsed !== void 0 && parsed <= 100 ? parsed : null;
|
|
8624
9419
|
}
|
|
8625
9420
|
function isoInstant3(value) {
|
|
@@ -8627,18 +9422,18 @@ function isoInstant3(value) {
|
|
|
8627
9422
|
const time = Date.parse(value);
|
|
8628
9423
|
if (Number.isFinite(time)) return new Date(time).toISOString();
|
|
8629
9424
|
}
|
|
8630
|
-
const numeric =
|
|
9425
|
+
const numeric = finiteNumber5(value);
|
|
8631
9426
|
if (numeric !== void 0 && numeric > 1e9) {
|
|
8632
9427
|
const ms = numeric > 1e12 ? numeric : numeric * 1e3;
|
|
8633
9428
|
return new Date(ms).toISOString();
|
|
8634
9429
|
}
|
|
8635
9430
|
return void 0;
|
|
8636
9431
|
}
|
|
8637
|
-
function
|
|
9432
|
+
function secondsUntil7(instant, now) {
|
|
8638
9433
|
if (!instant) return void 0;
|
|
8639
9434
|
return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
|
|
8640
9435
|
}
|
|
8641
|
-
function
|
|
9436
|
+
function isRecord7(value) {
|
|
8642
9437
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
8643
9438
|
}
|
|
8644
9439
|
function detectProviderKeyQuotaAdapter(baseUrl) {
|
|
@@ -8661,6 +9456,7 @@ function detectProviderKeyQuotaAdapter(baseUrl) {
|
|
|
8661
9456
|
}
|
|
8662
9457
|
if (host === "api.code.umans.ai") return "umans";
|
|
8663
9458
|
if (host === "api.synthetic.new") return "synthetic";
|
|
9459
|
+
if (host === "api.cline.bot") return "cline-pass";
|
|
8664
9460
|
return null;
|
|
8665
9461
|
}
|
|
8666
9462
|
function providerKeyQuotaUrl(adapter, baseUrl) {
|
|
@@ -8668,6 +9464,7 @@ function providerKeyQuotaUrl(adapter, baseUrl) {
|
|
|
8668
9464
|
if (adapter === "zai") return `${origin}/api/monitor/usage/quota/limit`;
|
|
8669
9465
|
if (adapter === "minimax-token-plan") return `${origin}/v1/token_plan/remains`;
|
|
8670
9466
|
if (adapter === "umans") return `${origin}/v1/usage`;
|
|
9467
|
+
if (adapter === "cline-pass") return `${origin}/api/v1/users/me/plan/usage-limits`;
|
|
8671
9468
|
return `${origin}/v2/quotas`;
|
|
8672
9469
|
}
|
|
8673
9470
|
function providerKeyQuotaAuthHeader(adapter, key) {
|
|
@@ -8679,7 +9476,7 @@ function zaiWindowDurationMs(item) {
|
|
|
8679
9476
|
case 3:
|
|
8680
9477
|
return count * HOUR_MS2;
|
|
8681
9478
|
case 4:
|
|
8682
|
-
return count *
|
|
9479
|
+
return count * DAY_MS3;
|
|
8683
9480
|
case 5:
|
|
8684
9481
|
return count * MONTH_MS;
|
|
8685
9482
|
case 6:
|
|
@@ -8692,8 +9489,8 @@ function zaiWindowIdLabel(durationMs) {
|
|
|
8692
9489
|
if (durationMs === WEEK_MS) return { id: "seven-day", label: "7 days" };
|
|
8693
9490
|
if (durationMs === 5 * HOUR_MS2) return { id: "five-hour", label: "5 hours" };
|
|
8694
9491
|
if (durationMs === MONTH_MS) return { id: "thirty-day", label: "30 days" };
|
|
8695
|
-
if (durationMs !== void 0 && durationMs %
|
|
8696
|
-
const days = durationMs /
|
|
9492
|
+
if (durationMs !== void 0 && durationMs % DAY_MS3 === 0) {
|
|
9493
|
+
const days = durationMs / DAY_MS3;
|
|
8697
9494
|
return { id: `${days}d`, label: `${days} day${days === 1 ? "" : "s"}` };
|
|
8698
9495
|
}
|
|
8699
9496
|
if (durationMs !== void 0 && durationMs % HOUR_MS2 === 0) {
|
|
@@ -8703,23 +9500,23 @@ function zaiWindowIdLabel(durationMs) {
|
|
|
8703
9500
|
return { id: "quota", label: "Quota" };
|
|
8704
9501
|
}
|
|
8705
9502
|
function parseZaiQuotaPayload(payload, now) {
|
|
8706
|
-
if (!
|
|
8707
|
-
const data =
|
|
9503
|
+
if (!isRecord7(payload)) return null;
|
|
9504
|
+
const data = isRecord7(payload["data"]) ? payload["data"] : payload;
|
|
8708
9505
|
if (payload["success"] === false) return null;
|
|
8709
9506
|
const limits = Array.isArray(data["limits"]) ? data["limits"] : [];
|
|
8710
9507
|
const byWindow = /* @__PURE__ */ new Map();
|
|
8711
9508
|
for (const raw of limits) {
|
|
8712
|
-
if (!
|
|
9509
|
+
if (!isRecord7(raw)) continue;
|
|
8713
9510
|
const item = raw;
|
|
8714
9511
|
if (item.type === void 0) continue;
|
|
8715
9512
|
const details = raw["usageDetails"];
|
|
8716
|
-
if (Array.isArray(details) && details.some((d) =>
|
|
9513
|
+
if (Array.isArray(details) && details.some((d) => isRecord7(d) && d["modelCode"] === "zread")) {
|
|
8717
9514
|
continue;
|
|
8718
9515
|
}
|
|
8719
9516
|
const durationMs = zaiWindowDurationMs(item);
|
|
8720
9517
|
const { id, label } = zaiWindowIdLabel(durationMs);
|
|
8721
|
-
const limit =
|
|
8722
|
-
const used =
|
|
9518
|
+
const limit = finiteNumber5(item.usage);
|
|
9519
|
+
const used = finiteNumber5(item.currentValue);
|
|
8723
9520
|
const fromAbsolute = limit !== void 0 && used !== void 0 && limit > 0 ? Math.min(100, used / limit * 100) : void 0;
|
|
8724
9521
|
const fromPercentage = finitePercent4(item.percentage) ?? void 0;
|
|
8725
9522
|
const usedPercent = fromAbsolute !== void 0 ? Math.round(fromAbsolute * 10) / 10 : fromPercentage;
|
|
@@ -8730,9 +9527,9 @@ function parseZaiQuotaPayload(payload, now) {
|
|
|
8730
9527
|
label,
|
|
8731
9528
|
scope: "all",
|
|
8732
9529
|
usedPercent,
|
|
8733
|
-
...durationMs !== void 0 ? { windowMinutes: Math.round(durationMs /
|
|
9530
|
+
...durationMs !== void 0 ? { windowMinutes: Math.round(durationMs / MINUTE_MS3) } : {},
|
|
8734
9531
|
...resetsAt !== void 0 ? { resetsAt } : {},
|
|
8735
|
-
remainingSeconds:
|
|
9532
|
+
remainingSeconds: secondsUntil7(resetsAt, now),
|
|
8736
9533
|
state: "fresh"
|
|
8737
9534
|
};
|
|
8738
9535
|
const existing = byWindow.get(id);
|
|
@@ -8746,21 +9543,21 @@ function parseZaiQuotaPayload(payload, now) {
|
|
|
8746
9543
|
var MINIMAX_STATUS_EXHAUSTED = 2;
|
|
8747
9544
|
var MINIMAX_SHARED_BUCKET = "general";
|
|
8748
9545
|
function parseMiniMaxBucket(value) {
|
|
8749
|
-
if (!
|
|
9546
|
+
if (!isRecord7(value)) return null;
|
|
8750
9547
|
const modelName = typeof value["model_name"] === "string" ? value["model_name"].trim() : "";
|
|
8751
9548
|
if (!modelName) return null;
|
|
8752
9549
|
const instant = (v) => {
|
|
8753
|
-
const n =
|
|
9550
|
+
const n = finiteNumber5(v);
|
|
8754
9551
|
return n !== void 0 && n > 1e9 ? n > 1e12 ? n : n * 1e3 : void 0;
|
|
8755
9552
|
};
|
|
8756
9553
|
return {
|
|
8757
9554
|
modelName,
|
|
8758
9555
|
intervalEnd: instant(value["end_time"]),
|
|
8759
|
-
intervalRemainingPercent:
|
|
8760
|
-
intervalStatus:
|
|
9556
|
+
intervalRemainingPercent: finiteNumber5(value["current_interval_remaining_percent"]),
|
|
9557
|
+
intervalStatus: finiteNumber5(value["current_interval_status"]),
|
|
8761
9558
|
weeklyEnd: instant(value["weekly_end_time"]),
|
|
8762
|
-
weeklyRemainingPercent:
|
|
8763
|
-
weeklyStatus:
|
|
9559
|
+
weeklyRemainingPercent: finiteNumber5(value["current_weekly_remaining_percent"]),
|
|
9560
|
+
weeklyStatus: finiteNumber5(value["current_weekly_status"])
|
|
8764
9561
|
};
|
|
8765
9562
|
}
|
|
8766
9563
|
function minimaxWindow(id, label, windowMinutes, resetsAtMs, remainingPercent, status, now) {
|
|
@@ -8773,14 +9570,14 @@ function minimaxWindow(id, label, windowMinutes, resetsAtMs, remainingPercent, s
|
|
|
8773
9570
|
usedPercent,
|
|
8774
9571
|
...windowMinutes !== void 0 ? { windowMinutes } : {},
|
|
8775
9572
|
...resetsAt !== void 0 ? { resetsAt } : {},
|
|
8776
|
-
remainingSeconds:
|
|
9573
|
+
remainingSeconds: secondsUntil7(resetsAt, now),
|
|
8777
9574
|
state: usedPercent !== null ? "fresh" : "unavailable"
|
|
8778
9575
|
};
|
|
8779
9576
|
}
|
|
8780
9577
|
function parseMiniMaxTokenPlanPayload(payload, now) {
|
|
8781
|
-
if (!
|
|
9578
|
+
if (!isRecord7(payload)) return null;
|
|
8782
9579
|
const baseResp = payload["base_resp"];
|
|
8783
|
-
if (!
|
|
9580
|
+
if (!isRecord7(baseResp) || baseResp["status_code"] !== 0) return null;
|
|
8784
9581
|
const buckets = Array.isArray(payload["model_remains"]) ? payload["model_remains"] : [];
|
|
8785
9582
|
let general = null;
|
|
8786
9583
|
for (const raw of buckets) {
|
|
@@ -8804,7 +9601,7 @@ function parseMiniMaxTokenPlanPayload(payload, now) {
|
|
|
8804
9601
|
minimaxWindow(
|
|
8805
9602
|
"seven-day",
|
|
8806
9603
|
"7 days",
|
|
8807
|
-
Math.round(WEEK_MS /
|
|
9604
|
+
Math.round(WEEK_MS / MINUTE_MS3),
|
|
8808
9605
|
general.weeklyEnd,
|
|
8809
9606
|
general.weeklyRemainingPercent,
|
|
8810
9607
|
general.weeklyStatus,
|
|
@@ -8813,15 +9610,15 @@ function parseMiniMaxTokenPlanPayload(payload, now) {
|
|
|
8813
9610
|
];
|
|
8814
9611
|
}
|
|
8815
9612
|
function parseUmansUsagePayload(payload, now) {
|
|
8816
|
-
if (!
|
|
8817
|
-
const limits =
|
|
8818
|
-
const requests = limits &&
|
|
8819
|
-
const usage =
|
|
8820
|
-
const window =
|
|
8821
|
-
const hardCap =
|
|
8822
|
-
const softLimit =
|
|
8823
|
-
const requestsInWindow =
|
|
8824
|
-
const weightedInWindow =
|
|
9613
|
+
if (!isRecord7(payload)) return null;
|
|
9614
|
+
const limits = isRecord7(payload["limits"]) ? payload["limits"] : void 0;
|
|
9615
|
+
const requests = limits && isRecord7(limits["requests"]) ? limits["requests"] : void 0;
|
|
9616
|
+
const usage = isRecord7(payload["usage"]) ? payload["usage"] : void 0;
|
|
9617
|
+
const window = isRecord7(payload["window"]) ? payload["window"] : void 0;
|
|
9618
|
+
const hardCap = finiteNumber5(requests?.["hard_cap"]);
|
|
9619
|
+
const softLimit = finiteNumber5(requests?.["limit"]);
|
|
9620
|
+
const requestsInWindow = finiteNumber5(usage?.["requests_in_window"]);
|
|
9621
|
+
const weightedInWindow = finiteNumber5(usage?.["weighted_in_window"]);
|
|
8825
9622
|
const resetsAt = isoInstant3(window?.["resets_at"]);
|
|
8826
9623
|
let usedPercent = null;
|
|
8827
9624
|
if (hardCap !== void 0 && hardCap > 0 && requestsInWindow !== void 0) {
|
|
@@ -8838,19 +9635,19 @@ function parseUmansUsagePayload(payload, now) {
|
|
|
8838
9635
|
usedPercent,
|
|
8839
9636
|
windowMinutes: 5 * 60,
|
|
8840
9637
|
...resetsAt !== void 0 ? { resetsAt } : {},
|
|
8841
|
-
remainingSeconds:
|
|
9638
|
+
remainingSeconds: secondsUntil7(resetsAt, now),
|
|
8842
9639
|
state: "fresh"
|
|
8843
9640
|
}
|
|
8844
9641
|
];
|
|
8845
9642
|
}
|
|
8846
9643
|
function parseSyntheticQuotasPayload(payload, now) {
|
|
8847
|
-
if (!
|
|
8848
|
-
const fiveHour =
|
|
8849
|
-
const weekly =
|
|
9644
|
+
if (!isRecord7(payload)) return null;
|
|
9645
|
+
const fiveHour = isRecord7(payload["rollingFiveHourLimit"]) ? payload["rollingFiveHourLimit"] : void 0;
|
|
9646
|
+
const weekly = isRecord7(payload["weeklyTokenLimit"]) ? payload["weeklyTokenLimit"] : void 0;
|
|
8850
9647
|
const windows = [];
|
|
8851
9648
|
if (fiveHour) {
|
|
8852
|
-
const max =
|
|
8853
|
-
const remaining =
|
|
9649
|
+
const max = finiteNumber5(fiveHour["max"]);
|
|
9650
|
+
const remaining = finiteNumber5(fiveHour["remaining"]);
|
|
8854
9651
|
const usedPercent = max !== void 0 && max > 0 && remaining !== void 0 ? Math.round(Math.min(100, (max - remaining) / max * 100) * 10) / 10 : null;
|
|
8855
9652
|
const resetsAt = isoInstant3(fiveHour["nextTickAt"]);
|
|
8856
9653
|
windows.push({
|
|
@@ -8860,12 +9657,12 @@ function parseSyntheticQuotasPayload(payload, now) {
|
|
|
8860
9657
|
usedPercent,
|
|
8861
9658
|
windowMinutes: 5 * 60,
|
|
8862
9659
|
...resetsAt !== void 0 ? { resetsAt } : {},
|
|
8863
|
-
remainingSeconds:
|
|
9660
|
+
remainingSeconds: secondsUntil7(resetsAt, now),
|
|
8864
9661
|
state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
|
|
8865
9662
|
});
|
|
8866
9663
|
}
|
|
8867
9664
|
if (weekly) {
|
|
8868
|
-
const percentRemaining =
|
|
9665
|
+
const percentRemaining = finiteNumber5(weekly["percentRemaining"]);
|
|
8869
9666
|
const usedPercent = percentRemaining !== void 0 ? Math.round(Math.min(100, Math.max(0, 100 - percentRemaining)) * 10) / 10 : null;
|
|
8870
9667
|
const resetsAt = isoInstant3(weekly["nextRegenAt"]);
|
|
8871
9668
|
windows.push({
|
|
@@ -8875,12 +9672,42 @@ function parseSyntheticQuotasPayload(payload, now) {
|
|
|
8875
9672
|
usedPercent,
|
|
8876
9673
|
windowMinutes: 7 * 24 * 60,
|
|
8877
9674
|
...resetsAt !== void 0 ? { resetsAt } : {},
|
|
8878
|
-
remainingSeconds:
|
|
9675
|
+
remainingSeconds: secondsUntil7(resetsAt, now),
|
|
8879
9676
|
state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
|
|
8880
9677
|
});
|
|
8881
9678
|
}
|
|
8882
9679
|
return windows.length > 0 ? windows : null;
|
|
8883
9680
|
}
|
|
9681
|
+
var CLINE_WINDOW_CONFIG = {
|
|
9682
|
+
five_hour: { id: "five-hour", label: "5 hours", minutes: 5 * 60 },
|
|
9683
|
+
weekly: { id: "seven-day", label: "7 days", minutes: 7 * 24 * 60 },
|
|
9684
|
+
monthly: { id: "thirty-day", label: "30 days", minutes: 30 * 24 * 60 }
|
|
9685
|
+
};
|
|
9686
|
+
function parseClinePassUsageLimitsPayload(payload, now) {
|
|
9687
|
+
if (!isRecord7(payload)) return null;
|
|
9688
|
+
const data = isRecord7(payload["data"]) ? payload["data"] : payload;
|
|
9689
|
+
const limits = Array.isArray(data["limits"]) ? data["limits"] : [];
|
|
9690
|
+
const windows = [];
|
|
9691
|
+
for (const raw of limits) {
|
|
9692
|
+
if (!isRecord7(raw)) continue;
|
|
9693
|
+
const config = CLINE_WINDOW_CONFIG[typeof raw["type"] === "string" ? raw["type"] : ""];
|
|
9694
|
+
if (!config) continue;
|
|
9695
|
+
const usedPercent = finitePercent4(raw["percentUsed"]);
|
|
9696
|
+
if (usedPercent === null) continue;
|
|
9697
|
+
const resetsAt = isoInstant3(raw["resetsAt"]);
|
|
9698
|
+
windows.push({
|
|
9699
|
+
id: config.id,
|
|
9700
|
+
label: config.label,
|
|
9701
|
+
scope: "all",
|
|
9702
|
+
usedPercent,
|
|
9703
|
+
windowMinutes: config.minutes,
|
|
9704
|
+
...resetsAt !== void 0 ? { resetsAt } : {},
|
|
9705
|
+
remainingSeconds: secondsUntil7(resetsAt, now),
|
|
9706
|
+
state: "fresh"
|
|
9707
|
+
});
|
|
9708
|
+
}
|
|
9709
|
+
return windows.length > 0 ? windows : null;
|
|
9710
|
+
}
|
|
8884
9711
|
|
|
8885
9712
|
// src/allowance/ProviderKeyQuotaService.ts
|
|
8886
9713
|
function parseQuotaPayload(adapter, payload, now) {
|
|
@@ -8893,6 +9720,8 @@ function parseQuotaPayload(adapter, payload, now) {
|
|
|
8893
9720
|
return parseUmansUsagePayload(payload, now);
|
|
8894
9721
|
case "synthetic":
|
|
8895
9722
|
return parseSyntheticQuotasPayload(payload, now);
|
|
9723
|
+
case "cline-pass":
|
|
9724
|
+
return parseClinePassUsageLimitsPayload(payload, now);
|
|
8896
9725
|
}
|
|
8897
9726
|
}
|
|
8898
9727
|
var PROVIDER_KEY_QUOTA_CACHE_MS = 5 * 6e4;
|
|
@@ -8912,7 +9741,7 @@ function rowKeyEntries(row) {
|
|
|
8912
9741
|
return [];
|
|
8913
9742
|
}
|
|
8914
9743
|
var ProviderKeyQuotaService = class {
|
|
8915
|
-
constructor(box, fetchImpl = (url, init) => (0,
|
|
9744
|
+
constructor(box, fetchImpl = (url, init) => (0, import_upstreamFetch10.fetchUpstream)(url, init, { redactBodies: true }), now = Date.now) {
|
|
8916
9745
|
this.box = box;
|
|
8917
9746
|
this.fetchImpl = fetchImpl;
|
|
8918
9747
|
this.now = now;
|
|
@@ -8974,7 +9803,10 @@ var ProviderKeyQuotaService = class {
|
|
|
8974
9803
|
headers: {
|
|
8975
9804
|
Authorization: providerKeyQuotaAuthHeader(adapter, key),
|
|
8976
9805
|
Accept: "application/json",
|
|
8977
|
-
"Content-Type": "application/json"
|
|
9806
|
+
"Content-Type": "application/json",
|
|
9807
|
+
// The row's static identity headers ride along — the Cline usage
|
|
9808
|
+
// endpoint sits behind the SAME client-identity 403 gate as inference.
|
|
9809
|
+
...(0, import_core4.mergeExtraHeaders)({}, row.extraHeaders)
|
|
8978
9810
|
},
|
|
8979
9811
|
signal: AbortSignal.timeout(15e3)
|
|
8980
9812
|
});
|
|
@@ -9045,7 +9877,7 @@ function defaultBillingDir(configPath) {
|
|
|
9045
9877
|
// src/image-generation/ImageDoctorService.ts
|
|
9046
9878
|
var import_image_generation = require("@omnicross/core/image-generation");
|
|
9047
9879
|
var import_outbound_api7 = require("@omnicross/core/outbound-api");
|
|
9048
|
-
var
|
|
9880
|
+
var import_subscriptions9 = require("@omnicross/subscriptions");
|
|
9049
9881
|
|
|
9050
9882
|
// src/image-generation/FileCodexImageCapabilityEvidenceSource.ts
|
|
9051
9883
|
var import_node_crypto13 = require("crypto");
|
|
@@ -9483,7 +10315,7 @@ function createImageDoctorService(options) {
|
|
|
9483
10315
|
paths,
|
|
9484
10316
|
ttlMs: config.evidenceTtlMs
|
|
9485
10317
|
}));
|
|
9486
|
-
const createLiveVerifier = options.createLiveVerifier ?? ((strategy, config) => (0,
|
|
10318
|
+
const createLiveVerifier = options.createLiveVerifier ?? ((strategy, config) => (0, import_subscriptions9.createCodexImageLiveVerifier)({
|
|
9487
10319
|
authStrategy: strategy,
|
|
9488
10320
|
generationTimeoutMs: config.queue.generationTimeoutMs
|
|
9489
10321
|
}));
|
|
@@ -9845,7 +10677,7 @@ var ImageCleanupService = class {
|
|
|
9845
10677
|
var import_node_crypto16 = require("crypto");
|
|
9846
10678
|
var import_image_generation5 = require("@omnicross/core/image-generation");
|
|
9847
10679
|
var import_outbound_api8 = require("@omnicross/core/outbound-api");
|
|
9848
|
-
var
|
|
10680
|
+
var import_subscriptions10 = require("@omnicross/subscriptions");
|
|
9849
10681
|
|
|
9850
10682
|
// src/image-generation/ImageApiRuntimeResolver.ts
|
|
9851
10683
|
var import_node_crypto14 = require("crypto");
|
|
@@ -10376,7 +11208,7 @@ function createImageRuntimeGeneration(options) {
|
|
|
10376
11208
|
now: options.now ?? Date.now,
|
|
10377
11209
|
referenceStore: options.storage.referenceStore,
|
|
10378
11210
|
stateStore: options.storage.stateStore
|
|
10379
|
-
}) : (0,
|
|
11211
|
+
}) : (0, import_subscriptions10.createCodexSubscriptionImageProvider)({
|
|
10380
11212
|
authStrategy,
|
|
10381
11213
|
evidenceSource: generationEvidenceSource,
|
|
10382
11214
|
executionScheduler: scheduler,
|
|
@@ -13520,7 +14352,7 @@ var ImageRuntimeManager = class {
|
|
|
13520
14352
|
};
|
|
13521
14353
|
|
|
13522
14354
|
// src/ports/ConfigFileProviderConfigSource.ts
|
|
13523
|
-
var
|
|
14355
|
+
var import_core5 = require("@omnicross/core");
|
|
13524
14356
|
var EMPTY_CHAIN = {
|
|
13525
14357
|
providerTransformers: [],
|
|
13526
14358
|
modelTransformers: []
|
|
@@ -13545,8 +14377,8 @@ var ConfigFileProviderConfigSource = class {
|
|
|
13545
14377
|
reloadHook;
|
|
13546
14378
|
constructor(config) {
|
|
13547
14379
|
for (const p of config.providers) this.providers.set(p.id, p);
|
|
13548
|
-
this.transformerService = new
|
|
13549
|
-
void (0,
|
|
14380
|
+
this.transformerService = new import_core5.TransformerService();
|
|
14381
|
+
void (0, import_core5.registerBuiltinTransformers)(this.transformerService);
|
|
13550
14382
|
}
|
|
13551
14383
|
// ── Reload hook (key-pool design D4) ───────────────────────────────────────
|
|
13552
14384
|
/**
|
|
@@ -13567,7 +14399,7 @@ var ConfigFileProviderConfigSource = class {
|
|
|
13567
14399
|
}
|
|
13568
14400
|
/** Await the built-in transformer registration (tests await this before dispatch). */
|
|
13569
14401
|
async ready() {
|
|
13570
|
-
await (0,
|
|
14402
|
+
await (0, import_core5.registerBuiltinTransformers)(this.transformerService);
|
|
13571
14403
|
}
|
|
13572
14404
|
// ── Hot-reload seam (admin dashboard, RT3 design D6) ───────────────────────
|
|
13573
14405
|
/**
|
|
@@ -13678,6 +14510,10 @@ function toLLMProvider(row) {
|
|
|
13678
14510
|
// `parseProviderInput`), so customizations are preserved (the row value wins).
|
|
13679
14511
|
apiModes: row.apiModes,
|
|
13680
14512
|
selectedApiModeId: row.selectedApiModeId,
|
|
14513
|
+
// Static extra request headers ride along verbatim (load-guarded — no
|
|
14514
|
+
// auth/content names); core's `getProviderHeaders` merges them into every
|
|
14515
|
+
// BYO request, and the same-format relay path inherits that funnel.
|
|
14516
|
+
extraHeaders: row.extraHeaders,
|
|
13681
14517
|
// Official-Anthropic signature handling only matters for the Anthropic
|
|
13682
14518
|
// ingress (deferred → 502); leave it off for the BYO transform path.
|
|
13683
14519
|
isOfficial: false
|
|
@@ -15043,7 +15879,7 @@ function bucketLabel(bucketStartTs, bucket) {
|
|
|
15043
15879
|
|
|
15044
15880
|
// src/ports/JsonOutboundKeyDb.ts
|
|
15045
15881
|
var import_node_fs19 = require("fs");
|
|
15046
|
-
var
|
|
15882
|
+
var import_core6 = require("@omnicross/core");
|
|
15047
15883
|
|
|
15048
15884
|
// src/ports/atomicFile.ts
|
|
15049
15885
|
var import_node_crypto22 = require("crypto");
|
|
@@ -15165,7 +16001,7 @@ var JsonOutboundKeyDb = class {
|
|
|
15165
16001
|
});
|
|
15166
16002
|
}
|
|
15167
16003
|
async outboundApiKeysSetPermissions(id, permissions) {
|
|
15168
|
-
const exact = (0,
|
|
16004
|
+
const exact = (0, import_core6.validateOutboundPermissions)(permissions);
|
|
15169
16005
|
return this.mutateRow(id, (row) => {
|
|
15170
16006
|
if (row.revokedAt !== null) return false;
|
|
15171
16007
|
row.allowedEndpoints = [...exact];
|
|
@@ -15602,9 +16438,9 @@ var import_node_fs24 = require("fs");
|
|
|
15602
16438
|
var import_node_path24 = require("path");
|
|
15603
16439
|
var import_SubscriptionAccountHealth2 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
|
|
15604
16440
|
var import_AccountAllowanceScheduling3 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
|
|
15605
|
-
var
|
|
16441
|
+
var import_upstreamFetch11 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
15606
16442
|
var import_SubscriptionIdentityStore2 = require("@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore");
|
|
15607
|
-
var
|
|
16443
|
+
var import_subscriptions11 = require("@omnicross/subscriptions");
|
|
15608
16444
|
|
|
15609
16445
|
// src/ports/account-sync.ts
|
|
15610
16446
|
function viewOf(tokens) {
|
|
@@ -15752,7 +16588,7 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
15752
16588
|
* a plaintext token pair into `upstream-trace.jsonl`.
|
|
15753
16589
|
*/
|
|
15754
16590
|
buildRefreshFetch(providerId, accountId) {
|
|
15755
|
-
return this.fetchImpl ?? ((url, init) => (0,
|
|
16591
|
+
return this.fetchImpl ?? ((url, init) => (0, import_upstreamFetch11.fetchUpstream)(url, init, { providerId, accountId, redactBodies: true }));
|
|
15756
16592
|
}
|
|
15757
16593
|
/**
|
|
15758
16594
|
* In-flight refresh coalescing. OAuth refresh tokens are
|
|
@@ -15793,7 +16629,7 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
15793
16629
|
* other hot reads. Never returns token material.
|
|
15794
16630
|
*/
|
|
15795
16631
|
getAccountProxy(providerId, accountId) {
|
|
15796
|
-
if (providerId !== "claude" && providerId !== "codex" && providerId !== "gemini" && providerId !== "opencodego" && providerId !== "kimi") {
|
|
16632
|
+
if (providerId !== "claude" && providerId !== "codex" && providerId !== "gemini" && providerId !== "opencodego" && providerId !== "kimi" && providerId !== "grok" && providerId !== "copilot") {
|
|
15797
16633
|
return void 0;
|
|
15798
16634
|
}
|
|
15799
16635
|
return getAccountProxy(this.readConfig(), providerId, accountId);
|
|
@@ -15812,7 +16648,7 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
15812
16648
|
const fingerprintOn = identityStore.isEnabled();
|
|
15813
16649
|
const now = Date.now();
|
|
15814
16650
|
const out = {};
|
|
15815
|
-
for (const provider of ["claude", "codex", "gemini", "opencodego", "kimi"]) {
|
|
16651
|
+
for (const provider of ["claude", "codex", "gemini", "opencodego", "kimi", "grok", "copilot"]) {
|
|
15816
16652
|
const sanitized = sanitizeAccounts(config, provider);
|
|
15817
16653
|
if (sanitized.length === 0) continue;
|
|
15818
16654
|
for (const account of sanitized) {
|
|
@@ -15878,7 +16714,7 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
15878
16714
|
this.materializeMigration(config);
|
|
15879
16715
|
const refreshFetch = this.buildRefreshFetch("claude", capturedId);
|
|
15880
16716
|
try {
|
|
15881
|
-
const result = await
|
|
16717
|
+
const result = await import_subscriptions11.claudeOAuth.refreshAccessToken(claude.refreshToken, refreshFetch);
|
|
15882
16718
|
const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
|
|
15883
16719
|
const next = {
|
|
15884
16720
|
...claude,
|
|
@@ -15913,7 +16749,7 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
15913
16749
|
this.materializeMigration(config);
|
|
15914
16750
|
const refreshFetch = this.buildRefreshFetch("codex", capturedId);
|
|
15915
16751
|
try {
|
|
15916
|
-
const result = await
|
|
16752
|
+
const result = await import_subscriptions11.codexOAuth.refreshAccessToken(codex.refreshToken, refreshFetch);
|
|
15917
16753
|
const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
|
|
15918
16754
|
const next = {
|
|
15919
16755
|
...codex,
|
|
@@ -15951,7 +16787,7 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
15951
16787
|
this.materializeMigration(config);
|
|
15952
16788
|
const refreshFetch = this.buildRefreshFetch("gemini", capturedId);
|
|
15953
16789
|
try {
|
|
15954
|
-
const result = await
|
|
16790
|
+
const result = await import_subscriptions11.geminiOAuth.refreshAccessToken(gemini.refreshToken, refreshFetch);
|
|
15955
16791
|
const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
|
|
15956
16792
|
const next = {
|
|
15957
16793
|
...gemini,
|
|
@@ -15987,10 +16823,10 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
15987
16823
|
this.materializeMigration(config);
|
|
15988
16824
|
const refreshFetch = this.buildRefreshFetch("kimi", capturedId);
|
|
15989
16825
|
try {
|
|
15990
|
-
const result = await
|
|
16826
|
+
const result = await import_subscriptions11.kimiOAuth.refreshAccessToken(
|
|
15991
16827
|
kimi.refreshToken,
|
|
15992
16828
|
refreshFetch,
|
|
15993
|
-
|
|
16829
|
+
import_subscriptions11.kimiOAuth.kimiFingerprintHeaders(kimi.deviceId)
|
|
15994
16830
|
);
|
|
15995
16831
|
const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
|
|
15996
16832
|
const next = {
|
|
@@ -16011,6 +16847,66 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
16011
16847
|
}
|
|
16012
16848
|
});
|
|
16013
16849
|
}
|
|
16850
|
+
/**
|
|
16851
|
+
* Refresh the Grok (xAI SuperGrok) OAuth access token. The token endpoint is
|
|
16852
|
+
* resolved through OIDC discovery on every refresh (process-cached 1h by the
|
|
16853
|
+
* flow module) so a rotated endpoint document is picked up without a daemon
|
|
16854
|
+
* restart. HONEST `false` when no refresh_token.
|
|
16855
|
+
*/
|
|
16856
|
+
async refreshGrokToken() {
|
|
16857
|
+
return this.coalesce("grok:active", async () => {
|
|
16858
|
+
const config = this.readConfig();
|
|
16859
|
+
const active = getActiveAccount(config, "grok");
|
|
16860
|
+
const grok = active?.tokens;
|
|
16861
|
+
if (!active || !grok?.refreshToken) return false;
|
|
16862
|
+
const capturedId = active.id;
|
|
16863
|
+
this.materializeMigration(config);
|
|
16864
|
+
const refreshFetch = this.buildRefreshFetch("grok", capturedId);
|
|
16865
|
+
try {
|
|
16866
|
+
const tokenEndpoint = await import_subscriptions11.grokOAuth.resolveGrokTokenEndpoint(refreshFetch);
|
|
16867
|
+
const result = await import_subscriptions11.grokOAuth.refreshGrokAccessToken(grok.refreshToken, tokenEndpoint, refreshFetch);
|
|
16868
|
+
const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
|
|
16869
|
+
const next = {
|
|
16870
|
+
...grok,
|
|
16871
|
+
accessToken: result.accessToken,
|
|
16872
|
+
refreshToken: result.refreshToken,
|
|
16873
|
+
expiresAt,
|
|
16874
|
+
status: "authorized",
|
|
16875
|
+
lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16876
|
+
errorMessage: void 0,
|
|
16877
|
+
syncWarning: void 0
|
|
16878
|
+
};
|
|
16879
|
+
this.writeBackById("grok", capturedId, next);
|
|
16880
|
+
return true;
|
|
16881
|
+
} catch (error) {
|
|
16882
|
+
this.markExpiredById("grok", capturedId, grok, error);
|
|
16883
|
+
return false;
|
|
16884
|
+
}
|
|
16885
|
+
});
|
|
16886
|
+
}
|
|
16887
|
+
/**
|
|
16888
|
+
* "Refresh" a GitHub Copilot token — there is nothing to refresh (ghu_
|
|
16889
|
+
* tokens are long-lived with no exchange endpoint). A call here means the
|
|
16890
|
+
* strategy saw a 401 (the token was revoked); mark the account `expired`
|
|
16891
|
+
* with a re-authenticate message and return `false` (the proxy then declines
|
|
16892
|
+
* the retry instead of looping on a dead token).
|
|
16893
|
+
*/
|
|
16894
|
+
async refreshCopilotToken() {
|
|
16895
|
+
return this.coalesce("copilot:active", async () => {
|
|
16896
|
+
const config = this.readConfig();
|
|
16897
|
+
const active = getActiveAccount(config, "copilot");
|
|
16898
|
+
const copilot = active?.tokens;
|
|
16899
|
+
if (!active || !copilot?.accessToken) return false;
|
|
16900
|
+
this.materializeMigration(config);
|
|
16901
|
+
this.markExpiredById(
|
|
16902
|
+
"copilot",
|
|
16903
|
+
active.id,
|
|
16904
|
+
copilot,
|
|
16905
|
+
new Error("GitHub Copilot tokens cannot be refreshed \u2014 re-authenticate the account")
|
|
16906
|
+
);
|
|
16907
|
+
return false;
|
|
16908
|
+
});
|
|
16909
|
+
}
|
|
16014
16910
|
/**
|
|
16015
16911
|
* Refresh a SPECIFIC managed account by id (background scheduler sweep and
|
|
16016
16912
|
* account-pool resolution). It uses only that account's stored refresh
|
|
@@ -16063,7 +16959,7 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
16063
16959
|
}
|
|
16064
16960
|
const oauth = account.tokens;
|
|
16065
16961
|
if (!oauth.accessToken) return null;
|
|
16066
|
-
if (providerId === "codex" || providerId === "gemini" || providerId === "kimi") {
|
|
16962
|
+
if (providerId === "codex" || providerId === "gemini" || providerId === "kimi" || providerId === "grok" || providerId === "copilot") {
|
|
16067
16963
|
const expiresAtMs = oauth.expiresAt ? Date.parse(oauth.expiresAt) : 0;
|
|
16068
16964
|
const expiringSoon = expiresAtMs > 0 && Date.now() >= expiresAtMs - ACCOUNT_REFRESH_LEAD_MS;
|
|
16069
16965
|
if (expiringSoon && oauth.refreshToken) {
|
|
@@ -16156,10 +17052,10 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
16156
17052
|
if (provider === "kimi") {
|
|
16157
17053
|
const account = accountId ? getAccountById(this.readConfig(), "kimi", accountId) : void 0;
|
|
16158
17054
|
const deviceId = account?.tokens?.deviceId;
|
|
16159
|
-
const r2 = await
|
|
17055
|
+
const r2 = await import_subscriptions11.kimiOAuth.refreshAccessToken(
|
|
16160
17056
|
refreshToken,
|
|
16161
17057
|
refreshFetch,
|
|
16162
|
-
|
|
17058
|
+
import_subscriptions11.kimiOAuth.kimiFingerprintHeaders(deviceId)
|
|
16163
17059
|
);
|
|
16164
17060
|
return {
|
|
16165
17061
|
accessToken: r2.accessToken,
|
|
@@ -16167,7 +17063,19 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
16167
17063
|
expiresAt: new Date(Date.now() + r2.expiresIn * 1e3).toISOString()
|
|
16168
17064
|
};
|
|
16169
17065
|
}
|
|
16170
|
-
|
|
17066
|
+
if (provider === "grok") {
|
|
17067
|
+
const tokenEndpoint = await import_subscriptions11.grokOAuth.resolveGrokTokenEndpoint(refreshFetch);
|
|
17068
|
+
const r2 = await import_subscriptions11.grokOAuth.refreshGrokAccessToken(refreshToken, tokenEndpoint, refreshFetch);
|
|
17069
|
+
return {
|
|
17070
|
+
accessToken: r2.accessToken,
|
|
17071
|
+
refreshToken: r2.refreshToken,
|
|
17072
|
+
expiresAt: new Date(Date.now() + r2.expiresIn * 1e3).toISOString()
|
|
17073
|
+
};
|
|
17074
|
+
}
|
|
17075
|
+
if (provider === "copilot") {
|
|
17076
|
+
throw new Error("GitHub Copilot tokens cannot be refreshed \u2014 re-authenticate the account");
|
|
17077
|
+
}
|
|
17078
|
+
const flow = provider === "claude" ? import_subscriptions11.claudeOAuth : provider === "codex" ? import_subscriptions11.codexOAuth : import_subscriptions11.geminiOAuth;
|
|
16171
17079
|
const r = await flow.refreshAccessToken(refreshToken, refreshFetch);
|
|
16172
17080
|
return {
|
|
16173
17081
|
accessToken: r.accessToken,
|
|
@@ -16410,7 +17318,7 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
16410
17318
|
};
|
|
16411
17319
|
|
|
16412
17320
|
// src/AccountHealthProbeScheduler.ts
|
|
16413
|
-
var
|
|
17321
|
+
var import_upstreamFetch12 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
16414
17322
|
|
|
16415
17323
|
// src/probe/CodexGenerationProbe.ts
|
|
16416
17324
|
var import_codexCliHeaders = require("@omnicross/core/provider-proxy/identity/codexCliHeaders");
|
|
@@ -16553,7 +17461,16 @@ var PROVIDER_PROBE_PLANS = {
|
|
|
16553
17461
|
// Kimi's `GET /coding/v1/usages` is a verified FREE authed GET (the allowance
|
|
16554
17462
|
// collector uses it), but the probe path also needs the fingerprint headers —
|
|
16555
17463
|
// keep the probe local until the collector covers the health surface.
|
|
16556
|
-
kimi: { kind: "local" }
|
|
17464
|
+
kimi: { kind: "local" },
|
|
17465
|
+
// Grok's billing proxy is a verified FREE authed GET (the allowance collector
|
|
17466
|
+
// uses it) but it REJECTS non-OAuth credentials and sits on a separate host
|
|
17467
|
+
// with its own product-gate header — keep the probe local, the collector
|
|
17468
|
+
// owns the health surface.
|
|
17469
|
+
grok: { kind: "local" },
|
|
17470
|
+
// The Copilot quota endpoint (copilot_internal/user) is a verified FREE
|
|
17471
|
+
// authed GET but lives on api.github.com with its own auth dialect and a
|
|
17472
|
+
// monthly-only window — the allowance collector owns the health surface.
|
|
17473
|
+
copilot: { kind: "local" }
|
|
16557
17474
|
};
|
|
16558
17475
|
function probePlanFor(providerId) {
|
|
16559
17476
|
return PROVIDER_PROBE_PLANS[providerId] ?? { kind: "local" };
|
|
@@ -16575,7 +17492,7 @@ var AccountHealthProbeScheduler = class {
|
|
|
16575
17492
|
this.logger = logger;
|
|
16576
17493
|
this.config = config;
|
|
16577
17494
|
this.now = opts.now ?? Date.now;
|
|
16578
|
-
this.fetchImpl = opts.fetchImpl ??
|
|
17495
|
+
this.fetchImpl = opts.fetchImpl ?? import_upstreamFetch12.fetchUpstream;
|
|
16579
17496
|
this.sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
16580
17497
|
this.planFor = opts.planFor ?? probePlanFor;
|
|
16581
17498
|
}
|
|
@@ -17476,7 +18393,7 @@ async function readAuditStats(auditDir, query2 = {}) {
|
|
|
17476
18393
|
}
|
|
17477
18394
|
|
|
17478
18395
|
// src/audit/AuditPruneSweeper.ts
|
|
17479
|
-
var
|
|
18396
|
+
var DAY_MS4 = 24 * 60 * 6e4;
|
|
17480
18397
|
var SWEEP_INTERVAL_MS2 = 60 * 6e4;
|
|
17481
18398
|
var ARCHIVE_BATCH = 64;
|
|
17482
18399
|
var AuditPruneSweeper = class {
|
|
@@ -17540,7 +18457,7 @@ var AuditPruneSweeper = class {
|
|
|
17540
18457
|
this.sweeping = true;
|
|
17541
18458
|
try {
|
|
17542
18459
|
if (!(0, import_node_fs27.existsSync)(this.auditDir)) return 0;
|
|
17543
|
-
const cutoff = this.todayMidnight() - (this.config.retentionDays - 1) *
|
|
18460
|
+
const cutoff = this.todayMidnight() - (this.config.retentionDays - 1) * DAY_MS4;
|
|
17544
18461
|
let removed = 0;
|
|
17545
18462
|
for (const name of (0, import_node_fs27.readdirSync)(this.auditDir)) {
|
|
17546
18463
|
const dateMs = auditFileDateMs(name);
|
|
@@ -17797,7 +18714,7 @@ async function closeAll(writers) {
|
|
|
17797
18714
|
// src/usage/UsagePruneSweeper.ts
|
|
17798
18715
|
var import_promises8 = require("fs/promises");
|
|
17799
18716
|
var import_node_path29 = require("path");
|
|
17800
|
-
var
|
|
18717
|
+
var DAY_MS5 = 24 * 60 * 6e4;
|
|
17801
18718
|
var SWEEP_INTERVAL_MS3 = 60 * 6e4;
|
|
17802
18719
|
var DEFAULT_USAGE_RETENTION_DAYS = 90;
|
|
17803
18720
|
var UsagePruneSweeper = class {
|
|
@@ -17854,7 +18771,7 @@ var UsagePruneSweeper = class {
|
|
|
17854
18771
|
this.sweeping = true;
|
|
17855
18772
|
try {
|
|
17856
18773
|
const retentionDays = this.config.retentionDays ?? DEFAULT_USAGE_RETENTION_DAYS;
|
|
17857
|
-
const cutoff = this.todayMidnight() - (retentionDays - 1) *
|
|
18774
|
+
const cutoff = this.todayMidnight() - (retentionDays - 1) * DAY_MS5;
|
|
17858
18775
|
let removed = 0;
|
|
17859
18776
|
for (const entry of await listUsageDays(this.usageDir)) {
|
|
17860
18777
|
if (!entry.hasShard) continue;
|
|
@@ -18273,7 +19190,7 @@ var AuditWriter = class {
|
|
|
18273
19190
|
var import_node_fs33 = require("fs");
|
|
18274
19191
|
var import_node_crypto24 = require("crypto");
|
|
18275
19192
|
var import_node_path33 = require("path");
|
|
18276
|
-
var
|
|
19193
|
+
var import_upstreamFetch13 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
18277
19194
|
|
|
18278
19195
|
// src/billing/billingFiles.ts
|
|
18279
19196
|
var BILLING_FILE_RE = /^billing-(\d{4})-(\d{2})-(\d{2})\.jsonl$/;
|
|
@@ -18296,7 +19213,7 @@ var BillingPublisher = class {
|
|
|
18296
19213
|
constructor(billingDir, logger, opts = {}) {
|
|
18297
19214
|
this.billingDir = billingDir;
|
|
18298
19215
|
this.logger = logger;
|
|
18299
|
-
this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0,
|
|
19216
|
+
this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch13.fetchUpstream)(url, init));
|
|
18300
19217
|
this.defer = opts.defer ?? ((fn) => setTimeout(fn, 0));
|
|
18301
19218
|
this.timeoutMs = opts.timeoutMs ?? BILLING_POST_TIMEOUT_MS;
|
|
18302
19219
|
this.now = opts.now ?? Date.now;
|
|
@@ -18546,7 +19463,7 @@ var BillingRetrySweeper = class {
|
|
|
18546
19463
|
// src/TokenRefreshScheduler.ts
|
|
18547
19464
|
var REFRESH_LEAD_MS2 = 5 * 6e4;
|
|
18548
19465
|
var SWEEP_INTERVAL_MS5 = 6e4;
|
|
18549
|
-
var OAUTH_PROVIDERS2 = ["claude", "codex", "gemini", "kimi"];
|
|
19466
|
+
var OAUTH_PROVIDERS2 = ["claude", "codex", "gemini", "kimi", "grok", "copilot"];
|
|
18550
19467
|
var TokenRefreshScheduler = class {
|
|
18551
19468
|
constructor(store, logger, intervalMs = SWEEP_INTERVAL_MS5, leadMs = REFRESH_LEAD_MS2) {
|
|
18552
19469
|
this.store = store;
|
|
@@ -18631,6 +19548,12 @@ var TokenRefreshScheduler = class {
|
|
|
18631
19548
|
return this.store.refreshGeminiToken();
|
|
18632
19549
|
case "kimi":
|
|
18633
19550
|
return this.store.refreshKimiToken();
|
|
19551
|
+
case "grok":
|
|
19552
|
+
return this.store.refreshGrokToken();
|
|
19553
|
+
// ghu_ tokens never near-expire (far-future expiresAt), so the sweep
|
|
19554
|
+
// never reaches this — the branch exists for union totality.
|
|
19555
|
+
case "copilot":
|
|
19556
|
+
return this.store.refreshCopilotToken();
|
|
18634
19557
|
}
|
|
18635
19558
|
}
|
|
18636
19559
|
};
|
|
@@ -18707,7 +19630,7 @@ function createRouteLeaseSubscriptionPreflight(credentials) {
|
|
|
18707
19630
|
|
|
18708
19631
|
// src/webhook/WebhookDispatcher.ts
|
|
18709
19632
|
var import_node_crypto25 = require("crypto");
|
|
18710
|
-
var
|
|
19633
|
+
var import_upstreamFetch14 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
18711
19634
|
var WEBHOOK_MAX_ATTEMPTS = 3;
|
|
18712
19635
|
var WEBHOOK_QUEUE_MAX = 1e3;
|
|
18713
19636
|
var WEBHOOK_SEND_TIMEOUT_MS = 1e4;
|
|
@@ -18727,7 +19650,7 @@ var WebhookDispatcher = class {
|
|
|
18727
19650
|
sleep;
|
|
18728
19651
|
now;
|
|
18729
19652
|
constructor(opts = {}) {
|
|
18730
|
-
this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0,
|
|
19653
|
+
this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch14.fetchUpstream)(url, init));
|
|
18731
19654
|
this.logger = opts.logger;
|
|
18732
19655
|
this.maxAttempts = opts.maxAttempts ?? WEBHOOK_MAX_ATTEMPTS;
|
|
18733
19656
|
this.queueMax = opts.queueMax ?? WEBHOOK_QUEUE_MAX;
|
|
@@ -18813,8 +19736,8 @@ var WebhookDispatcher = class {
|
|
|
18813
19736
|
signal: AbortSignal.timeout(this.timeoutMs)
|
|
18814
19737
|
});
|
|
18815
19738
|
return res.ok ? { ok: true, status: res.status } : { ok: false, status: res.status };
|
|
18816
|
-
} catch (
|
|
18817
|
-
return { ok: false, error:
|
|
19739
|
+
} catch (err8) {
|
|
19740
|
+
return { ok: false, error: err8 instanceof Error ? err8.message : String(err8) };
|
|
18818
19741
|
}
|
|
18819
19742
|
}
|
|
18820
19743
|
/**
|
|
@@ -18877,7 +19800,7 @@ function feishuText(event) {
|
|
|
18877
19800
|
// src/bootstrap.ts
|
|
18878
19801
|
var activeImageRuntimeBootstrapSession;
|
|
18879
19802
|
function createImageRuntimeBootstrapSession(initialGeneration) {
|
|
18880
|
-
const openAIOperationRegistry = new
|
|
19803
|
+
const openAIOperationRegistry = new import_core7.OpenAIOperationRegistry();
|
|
18881
19804
|
const imageRuntimeManager = new ImageRuntimeManager(initialGeneration);
|
|
18882
19805
|
const unregisterContributions = [];
|
|
18883
19806
|
try {
|
|
@@ -18956,12 +19879,12 @@ function buildDaemon(config, paths) {
|
|
|
18956
19879
|
setSecretBox(secretBox3);
|
|
18957
19880
|
setSecretBox2(secretBox3);
|
|
18958
19881
|
const decryptedConfig = decryptConfigSecrets(config, secretBox3);
|
|
18959
|
-
const accountAllowanceStore = new
|
|
19882
|
+
const accountAllowanceStore = new import_AccountAllowanceStore9.AccountAllowanceStore(
|
|
18960
19883
|
Date.now,
|
|
18961
19884
|
void 0,
|
|
18962
19885
|
new JsonAccountAllowancePersistence(defaultAccountAllowancePath(paths.configPath))
|
|
18963
19886
|
);
|
|
18964
|
-
(0,
|
|
19887
|
+
(0, import_AccountAllowanceStore9.setSharedAccountAllowanceStore)(accountAllowanceStore);
|
|
18965
19888
|
(0, import_AccountAllowanceScheduling5.getSharedAccountAllowanceScheduling)().configure(
|
|
18966
19889
|
(0, import_outbound_api10.normalizeServerConfig)(decryptedConfig.server).allowanceScheduling
|
|
18967
19890
|
);
|
|
@@ -18986,15 +19909,15 @@ function buildDaemon(config, paths) {
|
|
|
18986
19909
|
claudeAllowanceRefreshScheduler.configure(
|
|
18987
19910
|
(0, import_outbound_api10.normalizeServerConfig)(decryptedConfig.server).allowanceScheduling
|
|
18988
19911
|
);
|
|
18989
|
-
const subscriptionAccounts = new
|
|
18990
|
-
(0,
|
|
18991
|
-
const subscriptionRegistry = new
|
|
19912
|
+
const subscriptionAccounts = new import_subscriptions12.SubscriptionAccountService(credentialStore);
|
|
19913
|
+
(0, import_subscriptions12.setSubscriptionAccountService)(subscriptionAccounts);
|
|
19914
|
+
const subscriptionRegistry = new import_subscriptions12.SubscriptionProviderRegistry(
|
|
18992
19915
|
subscriptionAccounts,
|
|
18993
19916
|
credentialStore
|
|
18994
19917
|
);
|
|
18995
|
-
(0,
|
|
19918
|
+
(0, import_subscriptions12.setSubscriptionProviderRegistry)(subscriptionRegistry);
|
|
18996
19919
|
setServerProxyConfig(decryptedConfig.server?.proxy);
|
|
18997
|
-
(0,
|
|
19920
|
+
(0, import_upstreamFetch15.setUpstreamProxyResolver)(
|
|
18998
19921
|
createUpstreamProxyResolver({
|
|
18999
19922
|
getAccountProxy: (providerId, accountId) => credentialStore.getAccountProxy(providerId, accountId)
|
|
19000
19923
|
})
|
|
@@ -19018,7 +19941,7 @@ function buildDaemon(config, paths) {
|
|
|
19018
19941
|
const pricingEngine = new import_usage2.PricingEngine(pricingStore, logger, {
|
|
19019
19942
|
// Catalog egress follows the same global/env proxy policy as every other
|
|
19020
19943
|
// daemon upstream call; no provider/account override applies here.
|
|
19021
|
-
fetchImpl: ((input, init) => (0,
|
|
19944
|
+
fetchImpl: ((input, init) => (0, import_upstreamFetch15.fetchUpstream)(String(input), init ?? {}))
|
|
19022
19945
|
});
|
|
19023
19946
|
const pricingRefreshScheduler = new PricingRefreshScheduler(
|
|
19024
19947
|
pricingEngine,
|
|
@@ -19303,7 +20226,7 @@ function buildDaemon(config, paths) {
|
|
|
19303
20226
|
// — `server.proxy.byProvider[...]` was silently skipped — and the call was
|
|
19304
20227
|
// excluded from the upstream trace, so a failing login left no evidence.
|
|
19305
20228
|
// `redactBodies` keeps the code/verifier + minted token out of that trace.
|
|
19306
|
-
oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => (0,
|
|
20229
|
+
oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => (0, import_upstreamFetch15.fetchUpstream)(url, init, { providerId, redactBodies: true }),
|
|
19307
20230
|
subscriptionAccountAppender: credentialStore,
|
|
19308
20231
|
// Codex interactive OAuth (app-parity-2 child 5) — the async loopback flow store
|
|
19309
20232
|
// + the one-shot 127.0.0.1:1455 listener. Token captured + persisted daemon-side;
|
|
@@ -19315,6 +20238,9 @@ function buildDaemon(config, paths) {
|
|
|
19315
20238
|
// paste; the app shows the verification URL + user code and polls the
|
|
19316
20239
|
// token-free status). Token captured + persisted daemon-side.
|
|
19317
20240
|
kimiSessions: new CodexOAuthSessionStore(),
|
|
20241
|
+
// Grok interactive OAuth — the same async DEVICE-CODE shape as kimi.
|
|
20242
|
+
grokSessions: new CodexOAuthSessionStore(),
|
|
20243
|
+
copilotSessions: new CodexOAuthSessionStore(),
|
|
19318
20244
|
// Migration pack (app-parity child 6, design D2/D3) — the concrete credential
|
|
19319
20245
|
// store provides BOTH the full DECRYPTED read (`getFullConfig`, export) and
|
|
19320
20246
|
// the multi-account append (`appendProviderAccount`, import re-encrypts at-
|
|
@@ -19373,7 +20299,7 @@ function buildDaemon(config, paths) {
|
|
|
19373
20299
|
});
|
|
19374
20300
|
const webhookDispatcher = new WebhookDispatcher({
|
|
19375
20301
|
logger,
|
|
19376
|
-
fetchImpl: (url, init) => (0,
|
|
20302
|
+
fetchImpl: (url, init) => (0, import_upstreamFetch15.fetchUpstream)(url, init)
|
|
19377
20303
|
});
|
|
19378
20304
|
setWebhookRuntime(webhookDispatcher, (0, import_SubscriptionAccountHealth4.getSharedAccountHealth)());
|
|
19379
20305
|
const auditWriter = new AuditWriter(auditDir, logger);
|
|
@@ -19453,9 +20379,9 @@ function resetDaemonSingletonsForTests() {
|
|
|
19453
20379
|
(0, import_provider_proxy4.__resetProviderProxyForTests)();
|
|
19454
20380
|
(0, import_outbound_api10.__resetOutboundApiServerForTests)();
|
|
19455
20381
|
(0, import_subscriptionRegistryPort.setSubscriptionRegistryForOutbound)(null);
|
|
19456
|
-
(0,
|
|
19457
|
-
(0,
|
|
19458
|
-
(0,
|
|
20382
|
+
(0, import_subscriptions12.setSubscriptionProviderRegistry)(null);
|
|
20383
|
+
(0, import_subscriptions12.setSubscriptionAccountService)(null);
|
|
20384
|
+
(0, import_upstreamFetch15.setUpstreamProxyResolver)(null);
|
|
19459
20385
|
setServerProxyConfig(void 0);
|
|
19460
20386
|
(0, import_gemini_code_assist_resolver.setGeminiCodeAssistResolver)(null);
|
|
19461
20387
|
setSecretBox(null);
|
|
@@ -19464,7 +20390,7 @@ function resetDaemonSingletonsForTests() {
|
|
|
19464
20390
|
resetAuditRuntimeForTests();
|
|
19465
20391
|
resetBillingRuntimeForTests();
|
|
19466
20392
|
(0, import_SubscriptionIdentityStore3.__resetSharedIdentityStoreForTests)();
|
|
19467
|
-
(0,
|
|
20393
|
+
(0, import_AccountAllowanceStore9.__resetSharedAccountAllowanceStoreForTests)();
|
|
19468
20394
|
(0, import_AccountAllowanceScheduling5.__resetSharedAccountAllowanceSchedulingForTests)();
|
|
19469
20395
|
(0, import_usage2.__resetSharedUsageThroughputTrackerForTests)();
|
|
19470
20396
|
}
|