@omnicross/daemon 0.3.1 → 0.4.1
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 +1504 -269
- package/dist/cli.js +1475 -228
- package/dist/index.cjs +1400 -263
- package/dist/index.d.cts +215 -8
- package/dist/index.d.ts +215 -8
- package/dist/index.js +1373 -226
- 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
|
|
66
|
-
var
|
|
65
|
+
var import_core7 = require("@omnicross/core");
|
|
66
|
+
var import_GeminiCodeAssistProjectResolver2 = 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_AccountAllowanceStore10 = require("@omnicross/core/pipeline/AccountAllowanceStore");
|
|
72
72
|
var import_AccountAllowanceScheduling5 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
|
|
73
|
-
var
|
|
73
|
+
var import_upstreamFetch16 = 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_AccountAllowanceStore8 = 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) {
|
|
@@ -837,28 +1016,682 @@ function parseKimiUsagePayload(payload, now) {
|
|
|
837
1016
|
}
|
|
838
1017
|
}
|
|
839
1018
|
}
|
|
840
|
-
return [...byId.values()].sort((a, b) => (a.windowMinutes ?? Infinity) - (b.windowMinutes ?? Infinity)).slice(0, 4);
|
|
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
|
+
});
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
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;
|
|
1494
|
+
}
|
|
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) {
|
|
1500
|
+
this.credentials = credentials;
|
|
1501
|
+
this.store = store;
|
|
1502
|
+
this.fetchImpl = fetchImpl;
|
|
1503
|
+
this.now = now;
|
|
1504
|
+
}
|
|
1505
|
+
credentials;
|
|
1506
|
+
store;
|
|
1507
|
+
fetchImpl;
|
|
1508
|
+
now;
|
|
1509
|
+
inFlight = /* @__PURE__ */ new Map();
|
|
1510
|
+
async collectMany(accounts, options = {}) {
|
|
1511
|
+
const settled = await Promise.allSettled(
|
|
1512
|
+
accounts.map((account) => this.collect(account, options))
|
|
1513
|
+
);
|
|
1514
|
+
return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
|
|
1515
|
+
}
|
|
1516
|
+
collect(account, options = {}) {
|
|
1517
|
+
const now = this.now();
|
|
1518
|
+
if (account.tokens.authMethod !== "oauth") {
|
|
1519
|
+
const existing = this.store.get("copilot", account.id, now);
|
|
1520
|
+
if (existing?.windows.every((window) => window.state === "unsupported")) {
|
|
1521
|
+
return Promise.resolve(existing);
|
|
1522
|
+
}
|
|
1523
|
+
const snapshot = this.unsupportedSnapshot(account.id, now);
|
|
1524
|
+
this.store.set(snapshot);
|
|
1525
|
+
return Promise.resolve(snapshot);
|
|
1526
|
+
}
|
|
1527
|
+
const cached = this.store.get("copilot", account.id, now);
|
|
1528
|
+
if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) {
|
|
1529
|
+
return Promise.resolve(cached);
|
|
1530
|
+
}
|
|
1531
|
+
const running = this.inFlight.get(account.id);
|
|
1532
|
+
if (running) return running;
|
|
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));
|
|
1534
|
+
this.inFlight.set(account.id, promise);
|
|
1535
|
+
return promise;
|
|
1536
|
+
}
|
|
1537
|
+
isCacheValid(snapshot, now, refreshAheadMs) {
|
|
1538
|
+
if (snapshot.windows.every((window) => window.state === "unsupported")) return true;
|
|
1539
|
+
const expiresAt = snapshot.expiresAt ? Date.parse(snapshot.expiresAt) : 0;
|
|
1540
|
+
const ahead = typeof refreshAheadMs === "number" && Number.isFinite(refreshAheadMs) ? Math.max(0, refreshAheadMs) : 0;
|
|
1541
|
+
return Number.isFinite(expiresAt) && expiresAt > now + ahead;
|
|
1542
|
+
}
|
|
1543
|
+
async fetchAccount(accountId, tokens) {
|
|
1544
|
+
let accessToken = await this.credentials.getAccessTokenForAccount("copilot", accountId);
|
|
1545
|
+
if (!accessToken) return this.failureSnapshot(accountId, "copilot_usage_token_unavailable", this.now());
|
|
1546
|
+
let response = await this.request(accountId, accessToken, tokens);
|
|
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());
|
|
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
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
if (!response.ok) return this.failureSnapshot(accountId, "copilot_usage_http_error", this.now());
|
|
1558
|
+
let payload;
|
|
1559
|
+
try {
|
|
1560
|
+
payload = await response.json();
|
|
1561
|
+
} catch {
|
|
1562
|
+
return this.failureSnapshot(accountId, "copilot_usage_invalid_response", this.now());
|
|
1563
|
+
}
|
|
1564
|
+
const now = this.now();
|
|
1565
|
+
const windows = parseCopilotUserPayload(payload, now);
|
|
1566
|
+
const snapshot = {
|
|
1567
|
+
providerId: "copilot",
|
|
1568
|
+
accountId,
|
|
1569
|
+
source: "oauth-usage-api",
|
|
1570
|
+
observedAt: new Date(now).toISOString(),
|
|
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" }
|
|
1574
|
+
],
|
|
1575
|
+
...windows ? {} : { lastErrorCode: "copilot_usage_invalid_response" }
|
|
1576
|
+
};
|
|
1577
|
+
this.store.set(snapshot);
|
|
1578
|
+
return snapshot;
|
|
1579
|
+
}
|
|
1580
|
+
request(accountId, accessToken, tokens) {
|
|
1581
|
+
return this.fetchImpl(`${githubApiBase(tokens)}/copilot_internal/user`, {
|
|
1582
|
+
method: "GET",
|
|
1583
|
+
headers: {
|
|
1584
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1585
|
+
Accept: "application/json",
|
|
1586
|
+
"Content-Type": "application/json",
|
|
1587
|
+
...import_subscriptions6.COPILOT_GITHUB_HEADERS
|
|
1588
|
+
},
|
|
1589
|
+
signal: AbortSignal.timeout(15e3)
|
|
1590
|
+
}, accountId);
|
|
1591
|
+
}
|
|
1592
|
+
failureSnapshot(accountId, code, now) {
|
|
1593
|
+
const existing = this.store.get("copilot", accountId, now);
|
|
1594
|
+
const snapshot = existing ? {
|
|
1595
|
+
...existing,
|
|
1596
|
+
expiresAt: new Date(now + COPILOT_ALLOWANCE_CACHE_MS).toISOString(),
|
|
1597
|
+
windows: existing.windows.map((window) => ({
|
|
1598
|
+
...window,
|
|
1599
|
+
state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt ? "stale" : "unavailable"
|
|
1600
|
+
})),
|
|
1601
|
+
lastErrorCode: code
|
|
1602
|
+
} : {
|
|
1603
|
+
providerId: "copilot",
|
|
1604
|
+
accountId,
|
|
1605
|
+
source: "oauth-usage-api",
|
|
1606
|
+
observedAt: new Date(now).toISOString(),
|
|
1607
|
+
expiresAt: new Date(now + COPILOT_ALLOWANCE_CACHE_MS).toISOString(),
|
|
1608
|
+
windows: [
|
|
1609
|
+
{ id: "thirty-day", label: "Monthly", scope: "all", usedPercent: null, state: "unavailable" }
|
|
1610
|
+
],
|
|
1611
|
+
lastErrorCode: code
|
|
1612
|
+
};
|
|
1613
|
+
this.store.set(snapshot);
|
|
1614
|
+
return snapshot;
|
|
1615
|
+
}
|
|
1616
|
+
unsupportedSnapshot(accountId, now) {
|
|
1617
|
+
return {
|
|
1618
|
+
providerId: "copilot",
|
|
1619
|
+
accountId,
|
|
1620
|
+
source: "oauth-usage-api",
|
|
1621
|
+
observedAt: new Date(now).toISOString(),
|
|
1622
|
+
windows: [
|
|
1623
|
+
{ id: "thirty-day", label: "Monthly", scope: "all", usedPercent: null, state: "unsupported" }
|
|
1624
|
+
],
|
|
1625
|
+
lastErrorCode: "copilot_usage_unsupported_auth"
|
|
1626
|
+
};
|
|
1627
|
+
}
|
|
1628
|
+
};
|
|
1629
|
+
|
|
1630
|
+
// src/allowance/GeminiAllowanceCollector.ts
|
|
1631
|
+
var import_GeminiCodeAssistProjectResolver = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
|
|
1632
|
+
var import_AccountAllowanceStore6 = require("@omnicross/core/pipeline/AccountAllowanceStore");
|
|
1633
|
+
var import_upstreamFetch6 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
1634
|
+
var import_transformers = require("@omnicross/core/transformer/transformers");
|
|
1635
|
+
var GEMINI_ALLOWANCE_CACHE_MS = 5 * 6e4;
|
|
1636
|
+
function isRecord4(value) {
|
|
1637
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
841
1638
|
}
|
|
842
|
-
|
|
843
|
-
|
|
1639
|
+
function secondsUntil6(instant, now) {
|
|
1640
|
+
if (!instant) return void 0;
|
|
1641
|
+
return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
|
|
1642
|
+
}
|
|
1643
|
+
function parseGeminiQuotaPayload(payload, now) {
|
|
1644
|
+
if (!isRecord4(payload)) return null;
|
|
1645
|
+
const buckets = Array.isArray(payload["buckets"]) ? payload["buckets"] : [];
|
|
1646
|
+
const windows = [];
|
|
1647
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1648
|
+
for (const raw of buckets) {
|
|
1649
|
+
if (!isRecord4(raw)) continue;
|
|
1650
|
+
const modelId = typeof raw["modelId"] === "string" && raw["modelId"].trim() ? raw["modelId"].trim() : void 0;
|
|
1651
|
+
const id = `gemini:${modelId ?? "all"}`;
|
|
1652
|
+
if (seen.has(id)) continue;
|
|
1653
|
+
seen.add(id);
|
|
1654
|
+
const fractionRaw = typeof raw["remainingFraction"] === "number" ? raw["remainingFraction"] : Number(raw["remainingFraction"]);
|
|
1655
|
+
const usedPercent = Number.isFinite(fractionRaw) ? Math.round(Math.min(100, Math.max(0, (1 - Math.min(1, Math.max(0, fractionRaw))) * 100)) * 10) / 10 : null;
|
|
1656
|
+
const resetRaw = typeof raw["resetTime"] === "string" && raw["resetTime"].trim() ? raw["resetTime"] : void 0;
|
|
1657
|
+
const resetsAt = resetRaw !== void 0 && Number.isFinite(Date.parse(resetRaw)) ? new Date(Date.parse(resetRaw)).toISOString() : void 0;
|
|
1658
|
+
windows.push({
|
|
1659
|
+
id,
|
|
1660
|
+
label: modelId ? `Gemini ${modelId}` : "Gemini quota",
|
|
1661
|
+
scope: modelId ? "model-family" : "all",
|
|
1662
|
+
...modelId ? { modelFamily: modelId } : {},
|
|
1663
|
+
usedPercent,
|
|
1664
|
+
...resetsAt !== void 0 ? { resetsAt } : {},
|
|
1665
|
+
remainingSeconds: secondsUntil6(resetsAt, now),
|
|
1666
|
+
state: "fresh"
|
|
1667
|
+
});
|
|
1668
|
+
}
|
|
1669
|
+
return windows.length > 0 ? windows : null;
|
|
1670
|
+
}
|
|
1671
|
+
var GeminiAllowanceCollector = class {
|
|
1672
|
+
constructor(credentials, store = (0, import_AccountAllowanceStore6.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch6.fetchUpstream)(url, init, { providerId: "gemini", accountId, redactBodies: true }), now = Date.now, projectResolver = (0, import_GeminiCodeAssistProjectResolver.getGeminiCodeAssistProjectResolver)()) {
|
|
844
1673
|
this.credentials = credentials;
|
|
845
1674
|
this.store = store;
|
|
846
1675
|
this.fetchImpl = fetchImpl;
|
|
847
1676
|
this.now = now;
|
|
1677
|
+
this.projectResolver = projectResolver;
|
|
848
1678
|
}
|
|
849
1679
|
credentials;
|
|
850
1680
|
store;
|
|
851
1681
|
fetchImpl;
|
|
852
1682
|
now;
|
|
1683
|
+
projectResolver;
|
|
853
1684
|
inFlight = /* @__PURE__ */ new Map();
|
|
854
1685
|
async collectMany(accounts, options = {}) {
|
|
855
|
-
const settled = await Promise.allSettled(
|
|
1686
|
+
const settled = await Promise.allSettled(
|
|
1687
|
+
accounts.map((account) => this.collect(account, options))
|
|
1688
|
+
);
|
|
856
1689
|
return settled.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
|
|
857
1690
|
}
|
|
858
1691
|
collect(account, options = {}) {
|
|
859
1692
|
const now = this.now();
|
|
860
1693
|
if (account.tokens.authMethod !== "oauth") {
|
|
861
|
-
const existing = this.store.get("
|
|
1694
|
+
const existing = this.store.get("gemini", account.id, now);
|
|
862
1695
|
if (existing?.windows.every((window) => window.state === "unsupported")) {
|
|
863
1696
|
return Promise.resolve(existing);
|
|
864
1697
|
}
|
|
@@ -866,13 +1699,13 @@ var KimiAllowanceCollector = class {
|
|
|
866
1699
|
this.store.set(snapshot);
|
|
867
1700
|
return Promise.resolve(snapshot);
|
|
868
1701
|
}
|
|
869
|
-
const cached = this.store.get("
|
|
1702
|
+
const cached = this.store.get("gemini", account.id, now);
|
|
870
1703
|
if (!options.force && cached && this.isCacheValid(cached, now, options.refreshAheadMs)) {
|
|
871
1704
|
return Promise.resolve(cached);
|
|
872
1705
|
}
|
|
873
1706
|
const running = this.inFlight.get(account.id);
|
|
874
1707
|
if (running) return running;
|
|
875
|
-
const promise = this.fetchAccount(account.id
|
|
1708
|
+
const promise = this.fetchAccount(account.id).catch(() => this.failureSnapshot(account.id, "gemini_usage_request_failed", this.now())).finally(() => this.inFlight.delete(account.id));
|
|
876
1709
|
this.inFlight.set(account.id, promise);
|
|
877
1710
|
return promise;
|
|
878
1711
|
}
|
|
@@ -882,101 +1715,104 @@ var KimiAllowanceCollector = class {
|
|
|
882
1715
|
const ahead = typeof refreshAheadMs === "number" && Number.isFinite(refreshAheadMs) ? Math.max(0, refreshAheadMs) : 0;
|
|
883
1716
|
return Number.isFinite(expiresAt) && expiresAt > now + ahead;
|
|
884
1717
|
}
|
|
885
|
-
async fetchAccount(accountId
|
|
886
|
-
let accessToken = await this.credentials.getAccessTokenForAccount("
|
|
887
|
-
if (!accessToken) return this.failureSnapshot(accountId, "
|
|
888
|
-
let
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
if (!accessToken) return this.failureSnapshot(accountId, "kimi_usage_token_unavailable", this.now());
|
|
894
|
-
response = await this.request(accountId, accessToken, tokens);
|
|
1718
|
+
async fetchAccount(accountId) {
|
|
1719
|
+
let accessToken = await this.credentials.getAccessTokenForAccount("gemini", accountId);
|
|
1720
|
+
if (!accessToken) return this.failureSnapshot(accountId, "gemini_usage_token_unavailable", this.now());
|
|
1721
|
+
let project;
|
|
1722
|
+
try {
|
|
1723
|
+
project = await this.projectResolver.resolveProject(accessToken);
|
|
1724
|
+
} catch {
|
|
1725
|
+
project = void 0;
|
|
895
1726
|
}
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
this.
|
|
899
|
-
return
|
|
1727
|
+
let response = await this.request(accountId, accessToken, project);
|
|
1728
|
+
if (response.status === 401 || response.status === 403) {
|
|
1729
|
+
const refreshed = await this.credentials.refreshAccountToken("gemini", accountId);
|
|
1730
|
+
if (!refreshed) return this.failureSnapshot(accountId, "gemini_usage_unauthorized", this.now());
|
|
1731
|
+
accessToken = await this.credentials.getAccessTokenForAccount("gemini", accountId);
|
|
1732
|
+
if (!accessToken) return this.failureSnapshot(accountId, "gemini_usage_token_unavailable", this.now());
|
|
1733
|
+
response = await this.request(accountId, accessToken, project);
|
|
1734
|
+
if (response.status === 401 || response.status === 403) {
|
|
1735
|
+
return this.failureSnapshot(accountId, "gemini_usage_unauthorized", this.now());
|
|
1736
|
+
}
|
|
900
1737
|
}
|
|
901
|
-
if (!response.ok) return this.failureSnapshot(accountId, "
|
|
1738
|
+
if (!response.ok) return this.failureSnapshot(accountId, "gemini_usage_http_error", this.now());
|
|
902
1739
|
let payload;
|
|
903
1740
|
try {
|
|
904
1741
|
payload = await response.json();
|
|
905
1742
|
} catch {
|
|
906
|
-
return this.failureSnapshot(accountId, "
|
|
1743
|
+
return this.failureSnapshot(accountId, "gemini_usage_invalid_response", this.now());
|
|
907
1744
|
}
|
|
908
1745
|
const now = this.now();
|
|
909
|
-
const windows =
|
|
1746
|
+
const windows = parseGeminiQuotaPayload(payload, now);
|
|
910
1747
|
const snapshot = {
|
|
911
|
-
providerId: "
|
|
1748
|
+
providerId: "gemini",
|
|
912
1749
|
accountId,
|
|
913
1750
|
source: "oauth-usage-api",
|
|
914
1751
|
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" }
|
|
1752
|
+
expiresAt: new Date(now + GEMINI_ALLOWANCE_CACHE_MS).toISOString(),
|
|
1753
|
+
windows: windows ?? [
|
|
1754
|
+
{ id: "gemini-quota", label: "Gemini quota", scope: "all", usedPercent: null, state: "unavailable" }
|
|
919
1755
|
],
|
|
920
|
-
...windows
|
|
1756
|
+
...windows ? {} : { lastErrorCode: "gemini_usage_invalid_response" }
|
|
921
1757
|
};
|
|
922
1758
|
this.store.set(snapshot);
|
|
923
1759
|
return snapshot;
|
|
924
1760
|
}
|
|
925
|
-
request(accountId, accessToken,
|
|
926
|
-
return this.fetchImpl(
|
|
927
|
-
method: "
|
|
1761
|
+
request(accountId, accessToken, project) {
|
|
1762
|
+
return this.fetchImpl(`${(0, import_transformers.resolveCodeAssistEndpoint)()}/v1internal:retrieveUserQuota`, {
|
|
1763
|
+
method: "POST",
|
|
928
1764
|
headers: {
|
|
929
1765
|
Authorization: `Bearer ${accessToken}`,
|
|
930
1766
|
Accept: "application/json",
|
|
931
|
-
|
|
1767
|
+
"Content-Type": "application/json",
|
|
1768
|
+
...(0, import_transformers.getGeminiCliIdentityHeaders)()
|
|
932
1769
|
},
|
|
1770
|
+
body: JSON.stringify(project ? { project } : {}),
|
|
933
1771
|
signal: AbortSignal.timeout(15e3)
|
|
934
1772
|
}, accountId);
|
|
935
1773
|
}
|
|
936
1774
|
failureSnapshot(accountId, code, now) {
|
|
937
|
-
const existing = this.store.get("
|
|
1775
|
+
const existing = this.store.get("gemini", accountId, now);
|
|
938
1776
|
const snapshot = existing ? {
|
|
939
1777
|
...existing,
|
|
940
|
-
expiresAt: new Date(now +
|
|
1778
|
+
expiresAt: new Date(now + GEMINI_ALLOWANCE_CACHE_MS).toISOString(),
|
|
941
1779
|
windows: existing.windows.map((window) => ({
|
|
942
1780
|
...window,
|
|
943
1781
|
state: window.state === "unsupported" ? "unsupported" : window.usedPercent !== null || window.resetsAt ? "stale" : "unavailable"
|
|
944
1782
|
})),
|
|
945
1783
|
lastErrorCode: code
|
|
946
1784
|
} : {
|
|
947
|
-
providerId: "
|
|
1785
|
+
providerId: "gemini",
|
|
948
1786
|
accountId,
|
|
949
1787
|
source: "oauth-usage-api",
|
|
950
1788
|
observedAt: new Date(now).toISOString(),
|
|
951
|
-
expiresAt: new Date(now +
|
|
1789
|
+
expiresAt: new Date(now + GEMINI_ALLOWANCE_CACHE_MS).toISOString(),
|
|
952
1790
|
windows: [
|
|
953
|
-
{ id: "
|
|
954
|
-
{ id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unavailable" }
|
|
1791
|
+
{ id: "gemini-quota", label: "Gemini quota", scope: "all", usedPercent: null, state: "unavailable" }
|
|
955
1792
|
],
|
|
956
1793
|
lastErrorCode: code
|
|
957
1794
|
};
|
|
958
1795
|
this.store.set(snapshot);
|
|
959
1796
|
return snapshot;
|
|
960
1797
|
}
|
|
961
|
-
unsupportedSnapshot(accountId, now
|
|
1798
|
+
unsupportedSnapshot(accountId, now) {
|
|
962
1799
|
return {
|
|
963
|
-
providerId: "
|
|
1800
|
+
providerId: "gemini",
|
|
964
1801
|
accountId,
|
|
965
1802
|
source: "oauth-usage-api",
|
|
966
1803
|
observedAt: new Date(now).toISOString(),
|
|
967
1804
|
windows: [
|
|
968
|
-
{ id: "
|
|
969
|
-
{ id: "seven-day", label: "7 days", scope: "all", usedPercent: null, state: "unsupported" }
|
|
1805
|
+
{ id: "gemini-quota", label: "Gemini quota", scope: "all", usedPercent: null, state: "unsupported" }
|
|
970
1806
|
],
|
|
971
|
-
lastErrorCode:
|
|
1807
|
+
lastErrorCode: "gemini_usage_unsupported_auth"
|
|
972
1808
|
};
|
|
973
1809
|
}
|
|
974
1810
|
};
|
|
975
1811
|
|
|
976
1812
|
// src/allowance/OpenCodeGoAllowanceCollector.ts
|
|
977
|
-
var
|
|
978
|
-
var
|
|
979
|
-
var
|
|
1813
|
+
var import_AccountAllowanceStore7 = require("@omnicross/core/pipeline/AccountAllowanceStore");
|
|
1814
|
+
var import_upstreamFetch7 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
1815
|
+
var import_subscriptions7 = require("@omnicross/subscriptions");
|
|
980
1816
|
var OPENCODEGO_ALLOWANCE_CACHE_MS = 5 * 6e4;
|
|
981
1817
|
var OPENCODEGO_DEFAULT_GO_BASE = "https://opencode.ai/zen/go";
|
|
982
1818
|
function finitePercent3(value) {
|
|
@@ -989,7 +1825,7 @@ function isoInstant2(value) {
|
|
|
989
1825
|
const time = Date.parse(value);
|
|
990
1826
|
return Number.isFinite(time) ? new Date(time).toISOString() : void 0;
|
|
991
1827
|
}
|
|
992
|
-
function
|
|
1828
|
+
function secondsUntil7(instant, now) {
|
|
993
1829
|
if (!instant) return void 0;
|
|
994
1830
|
return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
|
|
995
1831
|
}
|
|
@@ -1004,12 +1840,12 @@ function windowFromPayload3(id, label, minutes, payload, now) {
|
|
|
1004
1840
|
usedPercent,
|
|
1005
1841
|
windowMinutes: minutes,
|
|
1006
1842
|
...resetsAt !== void 0 ? { resetsAt } : {},
|
|
1007
|
-
remainingSeconds:
|
|
1843
|
+
remainingSeconds: secondsUntil7(resetsAt, now),
|
|
1008
1844
|
state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
|
|
1009
1845
|
};
|
|
1010
1846
|
}
|
|
1011
1847
|
var OpenCodeGoAllowanceCollector = class {
|
|
1012
|
-
constructor(credentials, store = (0,
|
|
1848
|
+
constructor(credentials, store = (0, import_AccountAllowanceStore7.getSharedAccountAllowanceStore)(), fetchImpl = (url, init, accountId) => (0, import_upstreamFetch7.fetchUpstream)(url, init, { providerId: "opencodego", accountId, redactBodies: true }), now = Date.now) {
|
|
1013
1849
|
this.credentials = credentials;
|
|
1014
1850
|
this.store = store;
|
|
1015
1851
|
this.fetchImpl = fetchImpl;
|
|
@@ -1039,7 +1875,7 @@ var OpenCodeGoAllowanceCollector = class {
|
|
|
1039
1875
|
async fetchAccount(account) {
|
|
1040
1876
|
const apiKey = await this.credentials.getAccessTokenForAccount("opencodego", account.id);
|
|
1041
1877
|
if (!apiKey) return this.failureSnapshot(account.id, this.now());
|
|
1042
|
-
const base = account.tokens.baseUrl ? (0,
|
|
1878
|
+
const base = account.tokens.baseUrl ? (0, import_subscriptions7.normalizeOpenCodeGoBaseUrl)(account.tokens.baseUrl) : OPENCODEGO_DEFAULT_GO_BASE;
|
|
1043
1879
|
const response = await this.fetchImpl(`${base}/v1/usage`, {
|
|
1044
1880
|
method: "GET",
|
|
1045
1881
|
headers: { Authorization: `Bearer ${apiKey}`, Accept: "application/json" },
|
|
@@ -1114,7 +1950,7 @@ function codexUnavailable(accountId, now) {
|
|
|
1114
1950
|
};
|
|
1115
1951
|
}
|
|
1116
1952
|
var AccountAllowanceService = class {
|
|
1117
|
-
constructor(credentials, store = (0,
|
|
1953
|
+
constructor(credentials, store = (0, import_AccountAllowanceStore8.getSharedAccountAllowanceStore)(), collector, codexCollector, kimiCollector, opencodegoCollector, grokCollector, copilotCollector, geminiCollector, now = Date.now) {
|
|
1118
1954
|
this.credentials = credentials;
|
|
1119
1955
|
this.store = store;
|
|
1120
1956
|
this.now = now;
|
|
@@ -1122,6 +1958,9 @@ var AccountAllowanceService = class {
|
|
|
1122
1958
|
this.codexCollector = codexCollector ?? new CodexAllowanceCollector(credentials, store);
|
|
1123
1959
|
this.kimiCollector = kimiCollector ?? new KimiAllowanceCollector(credentials, store);
|
|
1124
1960
|
this.opencodegoCollector = opencodegoCollector ?? new OpenCodeGoAllowanceCollector(credentials, store);
|
|
1961
|
+
this.grokCollector = grokCollector ?? new GrokAllowanceCollector(credentials, store);
|
|
1962
|
+
this.copilotCollector = copilotCollector ?? new CopilotAllowanceCollector(credentials, store);
|
|
1963
|
+
this.geminiCollector = geminiCollector ?? new GeminiAllowanceCollector(credentials, store);
|
|
1125
1964
|
}
|
|
1126
1965
|
credentials;
|
|
1127
1966
|
store;
|
|
@@ -1129,7 +1968,10 @@ var AccountAllowanceService = class {
|
|
|
1129
1968
|
claudeCollector;
|
|
1130
1969
|
codexCollector;
|
|
1131
1970
|
kimiCollector;
|
|
1971
|
+
grokCollector;
|
|
1972
|
+
copilotCollector;
|
|
1132
1973
|
opencodegoCollector;
|
|
1974
|
+
geminiCollector;
|
|
1133
1975
|
/**
|
|
1134
1976
|
* Read all/filtered snapshots. Claude's and Codex's five-minute caches are
|
|
1135
1977
|
* refreshed lazily on read (Codex polls `/backend-api/wham/usage`; the
|
|
@@ -1163,11 +2005,29 @@ var AccountAllowanceService = class {
|
|
|
1163
2005
|
(account) => !filter.accountId || account.id === filter.accountId
|
|
1164
2006
|
);
|
|
1165
2007
|
if (wantsOpenCodeGo) await this.opencodegoCollector.collectMany(opencodegoAccounts);
|
|
2008
|
+
const wantsGrok = !filter.providerId || filter.providerId === "grok";
|
|
2009
|
+
const grokAccounts = (config.grokAccounts ?? []).filter(
|
|
2010
|
+
(account) => !filter.accountId || account.id === filter.accountId
|
|
2011
|
+
);
|
|
2012
|
+
if (wantsGrok) await this.grokCollector.collectMany(grokAccounts);
|
|
2013
|
+
const wantsCopilot = !filter.providerId || filter.providerId === "copilot";
|
|
2014
|
+
const copilotAccounts = (config.copilotAccounts ?? []).filter(
|
|
2015
|
+
(account) => !filter.accountId || account.id === filter.accountId
|
|
2016
|
+
);
|
|
2017
|
+
if (wantsCopilot) await this.copilotCollector.collectMany(copilotAccounts);
|
|
2018
|
+
const wantsGemini = !filter.providerId || filter.providerId === "gemini";
|
|
2019
|
+
const geminiAccounts = (config.geminiAccounts ?? []).filter(
|
|
2020
|
+
(account) => !filter.accountId || account.id === filter.accountId
|
|
2021
|
+
);
|
|
2022
|
+
if (wantsGemini) await this.geminiCollector.collectMany(geminiAccounts);
|
|
1166
2023
|
const known = /* @__PURE__ */ new Set();
|
|
1167
2024
|
if (wantsClaude) for (const account of claudeAccounts) known.add(`claude\0${account.id}`);
|
|
1168
2025
|
if (wantsCodex) for (const account of codexAccounts) known.add(`codex\0${account.id}`);
|
|
1169
2026
|
if (wantsKimi) for (const account of kimiAccounts) known.add(`kimi\0${account.id}`);
|
|
1170
2027
|
if (wantsOpenCodeGo) for (const account of opencodegoAccounts) known.add(`opencodego\0${account.id}`);
|
|
2028
|
+
if (wantsGrok) for (const account of grokAccounts) known.add(`grok\0${account.id}`);
|
|
2029
|
+
if (wantsCopilot) for (const account of copilotAccounts) known.add(`copilot\0${account.id}`);
|
|
2030
|
+
if (wantsGemini) for (const account of geminiAccounts) known.add(`gemini\0${account.id}`);
|
|
1171
2031
|
return this.store.list(filter).filter((snapshot) => known.has(`${snapshot.providerId}\0${snapshot.accountId}`));
|
|
1172
2032
|
}
|
|
1173
2033
|
knownAccounts(config) {
|
|
@@ -1175,7 +2035,10 @@ var AccountAllowanceService = class {
|
|
|
1175
2035
|
...(config.claudeAccounts ?? []).map((account) => ({ providerId: "claude", accountId: account.id })),
|
|
1176
2036
|
...(config.codexAccounts ?? []).map((account) => ({ providerId: "codex", accountId: account.id })),
|
|
1177
2037
|
...(config.kimiAccounts ?? []).map((account) => ({ providerId: "kimi", accountId: account.id })),
|
|
1178
|
-
...(config.opencodegoAccounts ?? []).map((account) => ({ providerId: "opencodego", accountId: account.id }))
|
|
2038
|
+
...(config.opencodegoAccounts ?? []).map((account) => ({ providerId: "opencodego", accountId: account.id })),
|
|
2039
|
+
...(config.grokAccounts ?? []).map((account) => ({ providerId: "grok", accountId: account.id })),
|
|
2040
|
+
...(config.copilotAccounts ?? []).map((account) => ({ providerId: "copilot", accountId: account.id })),
|
|
2041
|
+
...(config.geminiAccounts ?? []).map((account) => ({ providerId: "gemini", accountId: account.id }))
|
|
1179
2042
|
];
|
|
1180
2043
|
}
|
|
1181
2044
|
/** Force-refresh Claude usage for one account or every stored Claude account. */
|
|
@@ -1218,6 +2081,33 @@ var AccountAllowanceService = class {
|
|
|
1218
2081
|
);
|
|
1219
2082
|
return this.kimiCollector.collectMany(accounts, { force: true });
|
|
1220
2083
|
}
|
|
2084
|
+
/** Force-refresh Copilot usage (copilot_internal/user) for one/all accounts. */
|
|
2085
|
+
async refreshCopilot(accountId) {
|
|
2086
|
+
const config = await this.credentials.getFullConfig();
|
|
2087
|
+
this.store.pruneToKnownAccounts(this.knownAccounts(config));
|
|
2088
|
+
const accounts = (config.copilotAccounts ?? []).filter(
|
|
2089
|
+
(account) => !accountId || account.id === accountId
|
|
2090
|
+
);
|
|
2091
|
+
return this.copilotCollector.collectMany(accounts, { force: true });
|
|
2092
|
+
}
|
|
2093
|
+
/** Force-refresh Grok usage (CLI billing proxy) for one/all accounts. */
|
|
2094
|
+
async refreshGrok(accountId) {
|
|
2095
|
+
const config = await this.credentials.getFullConfig();
|
|
2096
|
+
this.store.pruneToKnownAccounts(this.knownAccounts(config));
|
|
2097
|
+
const accounts = (config.grokAccounts ?? []).filter(
|
|
2098
|
+
(account) => !accountId || account.id === accountId
|
|
2099
|
+
);
|
|
2100
|
+
return this.grokCollector.collectMany(accounts, { force: true });
|
|
2101
|
+
}
|
|
2102
|
+
/** Force-refresh Gemini usage (Code Assist retrieveUserQuota) for one/all accounts. */
|
|
2103
|
+
async refreshGemini(accountId) {
|
|
2104
|
+
const config = await this.credentials.getFullConfig();
|
|
2105
|
+
this.store.pruneToKnownAccounts(this.knownAccounts(config));
|
|
2106
|
+
const accounts = (config.geminiAccounts ?? []).filter(
|
|
2107
|
+
(account) => !accountId || account.id === accountId
|
|
2108
|
+
);
|
|
2109
|
+
return this.geminiCollector.collectMany(accounts, { force: true });
|
|
2110
|
+
}
|
|
1221
2111
|
/**
|
|
1222
2112
|
* Keep Claude + Codex + Kimi snapshots warm for allowance-aware routing. All
|
|
1223
2113
|
* collectors preserve their cache + per-account in-flight coalescing; a tick
|
|
@@ -1232,6 +2122,9 @@ var AccountAllowanceService = class {
|
|
|
1232
2122
|
await this.codexCollector.collectMany(config.codexAccounts ?? [], { refreshAheadMs });
|
|
1233
2123
|
await this.kimiCollector.collectMany(config.kimiAccounts ?? [], { refreshAheadMs });
|
|
1234
2124
|
await this.opencodegoCollector.collectMany(config.opencodegoAccounts ?? [], { refreshAheadMs });
|
|
2125
|
+
await this.grokCollector.collectMany(config.grokAccounts ?? [], { refreshAheadMs });
|
|
2126
|
+
await this.copilotCollector.collectMany(config.copilotAccounts ?? [], { refreshAheadMs });
|
|
2127
|
+
await this.geminiCollector.collectMany(config.geminiAccounts ?? [], { refreshAheadMs });
|
|
1235
2128
|
}
|
|
1236
2129
|
/** Remove a cache row as soon as an account is deleted by the admin path. */
|
|
1237
2130
|
removeAccountSnapshot(providerId, accountId) {
|
|
@@ -1326,7 +2219,7 @@ var ClaudeAllowanceRefreshScheduler = class {
|
|
|
1326
2219
|
var import_node_crypto2 = require("crypto");
|
|
1327
2220
|
var import_node_fs = require("fs");
|
|
1328
2221
|
var import_node_path = require("path");
|
|
1329
|
-
var
|
|
2222
|
+
var import_AccountAllowanceStore9 = require("@omnicross/core/pipeline/AccountAllowanceStore");
|
|
1330
2223
|
var ACCOUNT_ALLOWANCE_CACHE_VERSION = 1;
|
|
1331
2224
|
var MAX_PERSISTED_ALLOWANCE_SNAPSHOTS = 256;
|
|
1332
2225
|
var MAX_ALLOWANCE_CACHE_BYTES = 1e6;
|
|
@@ -1355,7 +2248,7 @@ var JsonAccountAllowancePersistence = class {
|
|
|
1355
2248
|
save(snapshots) {
|
|
1356
2249
|
const rows = [];
|
|
1357
2250
|
for (const snapshot of snapshots) {
|
|
1358
|
-
const normalized2 = (0,
|
|
2251
|
+
const normalized2 = (0, import_AccountAllowanceStore9.normalizeAccountAllowanceSnapshot)(snapshot);
|
|
1359
2252
|
if (!normalized2) continue;
|
|
1360
2253
|
rows.push(normalized2);
|
|
1361
2254
|
if (rows.length >= MAX_PERSISTED_ALLOWANCE_SNAPSHOTS) break;
|
|
@@ -1638,7 +2531,8 @@ var import_outbound_api5 = require("@omnicross/core/outbound-api");
|
|
|
1638
2531
|
var import_image_generation_types = require("@omnicross/contracts/image-generation-types");
|
|
1639
2532
|
var import_AccountAllowanceScheduling2 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
|
|
1640
2533
|
var import_SubscriptionAccountHealth = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
|
|
1641
|
-
var
|
|
2534
|
+
var import_upstreamFetch10 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
2535
|
+
var import_core3 = require("@omnicross/core");
|
|
1642
2536
|
|
|
1643
2537
|
// src/image-generation/imagesConfigValidation.ts
|
|
1644
2538
|
var import_outbound_api = require("@omnicross/core/outbound-api");
|
|
@@ -1934,6 +2828,7 @@ async function applyServerConfigTransaction(current, next, deps) {
|
|
|
1934
2828
|
|
|
1935
2829
|
// src/config.ts
|
|
1936
2830
|
var import_node_fs4 = require("fs");
|
|
2831
|
+
var import_core = require("@omnicross/core");
|
|
1937
2832
|
|
|
1938
2833
|
// src/secrets/envelope.ts
|
|
1939
2834
|
var import_node_crypto4 = require("crypto");
|
|
@@ -2345,6 +3240,18 @@ var FORMAT_AXIS_TRANSFORMERS = [
|
|
|
2345
3240
|
"openai-response",
|
|
2346
3241
|
"gemini-code-assist"
|
|
2347
3242
|
];
|
|
3243
|
+
function validateExtraHeaders(raw) {
|
|
3244
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
3245
|
+
const reserved = import_core.EXTRA_HEADER_RESERVED_NAMES;
|
|
3246
|
+
const out = {};
|
|
3247
|
+
for (const [name, value] of Object.entries(raw)) {
|
|
3248
|
+
if (!name.trim()) continue;
|
|
3249
|
+
if (typeof value !== "string") continue;
|
|
3250
|
+
if (reserved.has(name.toLowerCase())) continue;
|
|
3251
|
+
out[name] = value;
|
|
3252
|
+
}
|
|
3253
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
3254
|
+
}
|
|
2348
3255
|
function validateApiKeys(raw) {
|
|
2349
3256
|
if (!Array.isArray(raw)) return void 0;
|
|
2350
3257
|
const out = [];
|
|
@@ -2558,6 +3465,9 @@ function validateProvider(raw, index) {
|
|
|
2558
3465
|
apiVersion,
|
|
2559
3466
|
maxConcurrency,
|
|
2560
3467
|
modelsEndpoint,
|
|
3468
|
+
// Static extra headers: load-guard (reserved names dropped), collapse-to-
|
|
3469
|
+
// undefined; enforced by the outbound header funnel + admin probes.
|
|
3470
|
+
extraHeaders: validateExtraHeaders(p["extraHeaders"]),
|
|
2561
3471
|
// Provider transformer config (app-parity child 5): load-guard, collapse-to-
|
|
2562
3472
|
// undefined; non-secret; ENFORCED via resolveTransformerChain (parity-2 child 2).
|
|
2563
3473
|
// Format-axis entries are stripped by `migrateFormatAxis` — `use[]` is the
|
|
@@ -2627,7 +3537,7 @@ var import_node_crypto6 = require("crypto");
|
|
|
2627
3537
|
var import_node_fs6 = require("fs");
|
|
2628
3538
|
var import_node_os3 = require("os");
|
|
2629
3539
|
var import_node_path6 = require("path");
|
|
2630
|
-
var
|
|
3540
|
+
var import_core2 = require("@omnicross/core");
|
|
2631
3541
|
|
|
2632
3542
|
// src/integrations/codexAuthHelper.ts
|
|
2633
3543
|
var import_node_path4 = require("path");
|
|
@@ -3108,7 +4018,7 @@ var IntegrationManager = class {
|
|
|
3108
4018
|
if (!secret) {
|
|
3109
4019
|
throw new IntegrationConflictError("The selected access key cannot be revealed and cannot power a CLI integration.");
|
|
3110
4020
|
}
|
|
3111
|
-
const effective = [...(0,
|
|
4021
|
+
const effective = [...(0, import_core2.effectiveOutboundPermissions)(row.allowedEndpoints)];
|
|
3112
4022
|
const previousPermissions = row.allowedEndpoints === void 0 ? [...effective] : [...row.allowedEndpoints];
|
|
3113
4023
|
const nextPermissions = [...effective];
|
|
3114
4024
|
for (const required of REQUIRED_PERMISSIONS[client]) {
|
|
@@ -3206,7 +4116,7 @@ var IntegrationManager = class {
|
|
|
3206
4116
|
return { binding, row, secret, created: false };
|
|
3207
4117
|
}
|
|
3208
4118
|
async createManagedClientKey(client, state) {
|
|
3209
|
-
const created = await (0,
|
|
4119
|
+
const created = await (0, import_core2.createIntegrationKey)(
|
|
3210
4120
|
this.options.keyDb,
|
|
3211
4121
|
`Omnicross ${displayClient(client)} integration`,
|
|
3212
4122
|
[...REQUIRED_PERMISSIONS[client]]
|
|
@@ -3298,7 +4208,7 @@ var IntegrationManager = class {
|
|
|
3298
4208
|
const row = rows.find((candidate) => candidate.id === keyId);
|
|
3299
4209
|
if (!row) return { usable: false, message: "The bound access key no longer exists." };
|
|
3300
4210
|
const secret = legacy?.secret ?? await this.options.keyDb.outboundApiKeysReveal(keyId) ?? void 0;
|
|
3301
|
-
const allowedEndpoints = [...(0,
|
|
4211
|
+
const allowedEndpoints = [...(0, import_core2.effectiveOutboundPermissions)(row.allowedEndpoints)];
|
|
3302
4212
|
const status = {
|
|
3303
4213
|
id: row.id,
|
|
3304
4214
|
name: row.name,
|
|
@@ -3342,7 +4252,7 @@ var IntegrationManager = class {
|
|
|
3342
4252
|
}
|
|
3343
4253
|
};
|
|
3344
4254
|
function hasRequiredPermissions(row, client) {
|
|
3345
|
-
const allowed = (0,
|
|
4255
|
+
const allowed = (0, import_core2.effectiveOutboundPermissions)(row.allowedEndpoints);
|
|
3346
4256
|
return REQUIRED_PERMISSIONS[client].every((permission) => allowed.includes(permission));
|
|
3347
4257
|
}
|
|
3348
4258
|
function samePermissions(a, b) {
|
|
@@ -3516,7 +4426,8 @@ function listMappablePresets() {
|
|
|
3516
4426
|
description: preset.description,
|
|
3517
4427
|
features: preset.features,
|
|
3518
4428
|
website: preset.website,
|
|
3519
|
-
modelsEndpoint: preset.modelsEndpoint
|
|
4429
|
+
modelsEndpoint: preset.modelsEndpoint,
|
|
4430
|
+
extraHeaders: preset.extraHeaders
|
|
3520
4431
|
});
|
|
3521
4432
|
}
|
|
3522
4433
|
return { mappable, excluded };
|
|
@@ -3606,11 +4517,11 @@ function preserveOutboundProxySecrets(incoming, current) {
|
|
|
3606
4517
|
}
|
|
3607
4518
|
|
|
3608
4519
|
// src/proxy/upstreamProxyResolver.ts
|
|
3609
|
-
var
|
|
4520
|
+
var import_upstreamFetch8 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
3610
4521
|
var serverProxy;
|
|
3611
4522
|
function setServerProxyConfig(proxy) {
|
|
3612
4523
|
serverProxy = proxy;
|
|
3613
|
-
(0,
|
|
4524
|
+
(0, import_upstreamFetch8.bumpUpstreamProxyGeneration)();
|
|
3614
4525
|
}
|
|
3615
4526
|
function getServerProxyConfig() {
|
|
3616
4527
|
return serverProxy;
|
|
@@ -3678,7 +4589,7 @@ function createUpstreamProxyResolver(src = {}) {
|
|
|
3678
4589
|
}
|
|
3679
4590
|
|
|
3680
4591
|
// src/admin/accountsOAuth.ts
|
|
3681
|
-
var
|
|
4592
|
+
var import_subscriptions8 = require("@omnicross/subscriptions");
|
|
3682
4593
|
|
|
3683
4594
|
// src/admin/accountsWrite.ts
|
|
3684
4595
|
var VALID_PROVIDER_IDS = [
|
|
@@ -3686,7 +4597,9 @@ var VALID_PROVIDER_IDS = [
|
|
|
3686
4597
|
"codex",
|
|
3687
4598
|
"gemini",
|
|
3688
4599
|
"opencodego",
|
|
3689
|
-
"kimi"
|
|
4600
|
+
"kimi",
|
|
4601
|
+
"grok",
|
|
4602
|
+
"copilot"
|
|
3690
4603
|
];
|
|
3691
4604
|
function asSubscriptionProviderId(id) {
|
|
3692
4605
|
return VALID_PROVIDER_IDS.includes(id) ? id : null;
|
|
@@ -3834,6 +4747,40 @@ function validateKimi(body) {
|
|
|
3834
4747
|
copyOptional(out, body, ["accessToken", "refreshToken", "expiresAt", "accountId", "deviceId", "lastRefreshedAt", "errorMessage"]);
|
|
3835
4748
|
return out;
|
|
3836
4749
|
}
|
|
4750
|
+
function validateGrok(body) {
|
|
4751
|
+
const authMethod = str(body["authMethod"]);
|
|
4752
|
+
const status = str(body["status"]);
|
|
4753
|
+
if (!authMethod || !OAUTH_AUTH_METHODS.has(authMethod)) return null;
|
|
4754
|
+
if (!status || !TOKEN_STATUSES.has(status)) return null;
|
|
4755
|
+
const out = {
|
|
4756
|
+
authMethod,
|
|
4757
|
+
status
|
|
4758
|
+
};
|
|
4759
|
+
copyOptional(out, body, ["accessToken", "refreshToken", "expiresAt", "accountId", "lastRefreshedAt", "errorMessage"]);
|
|
4760
|
+
return out;
|
|
4761
|
+
}
|
|
4762
|
+
function validateCopilot(body) {
|
|
4763
|
+
const authMethod = str(body["authMethod"]);
|
|
4764
|
+
const status = str(body["status"]);
|
|
4765
|
+
if (!authMethod || !OAUTH_AUTH_METHODS.has(authMethod)) return null;
|
|
4766
|
+
if (!status || !TOKEN_STATUSES.has(status)) return null;
|
|
4767
|
+
const out = {
|
|
4768
|
+
authMethod,
|
|
4769
|
+
status
|
|
4770
|
+
};
|
|
4771
|
+
copyOptional(out, body, [
|
|
4772
|
+
"accessToken",
|
|
4773
|
+
"refreshToken",
|
|
4774
|
+
"expiresAt",
|
|
4775
|
+
"accountId",
|
|
4776
|
+
"email",
|
|
4777
|
+
"apiEndpoint",
|
|
4778
|
+
"enterpriseUrl",
|
|
4779
|
+
"lastRefreshedAt",
|
|
4780
|
+
"errorMessage"
|
|
4781
|
+
]);
|
|
4782
|
+
return out;
|
|
4783
|
+
}
|
|
3837
4784
|
function validateOpenCodeGo(body) {
|
|
3838
4785
|
const authMethod = str(body["authMethod"]);
|
|
3839
4786
|
const status = str(body["status"]);
|
|
@@ -3871,6 +4818,10 @@ function validateTokenBody(providerId, body) {
|
|
|
3871
4818
|
return validateOpenCodeGo(body);
|
|
3872
4819
|
case "kimi":
|
|
3873
4820
|
return validateKimi(body);
|
|
4821
|
+
case "grok":
|
|
4822
|
+
return validateGrok(body);
|
|
4823
|
+
case "copilot":
|
|
4824
|
+
return validateCopilot(body);
|
|
3874
4825
|
default:
|
|
3875
4826
|
return null;
|
|
3876
4827
|
}
|
|
@@ -3900,37 +4851,37 @@ async function statusEntryFor(reader, providerId) {
|
|
|
3900
4851
|
|
|
3901
4852
|
// src/admin/accountsOAuth.ts
|
|
3902
4853
|
var OAUTH_HTTP_PROVIDERS = /* @__PURE__ */ new Set(["claude", "gemini"]);
|
|
3903
|
-
function
|
|
4854
|
+
function err5(status, message) {
|
|
3904
4855
|
return { status, body: { error: { type: "admin_api_error", message } } };
|
|
3905
4856
|
}
|
|
3906
4857
|
function handleOAuthStart(providerId, deps) {
|
|
3907
4858
|
if (!OAUTH_HTTP_PROVIDERS.has(providerId)) {
|
|
3908
|
-
return
|
|
4859
|
+
return err5(400, `oauth not available for provider '${providerId}'`);
|
|
3909
4860
|
}
|
|
3910
|
-
const flow = providerId === "claude" ?
|
|
4861
|
+
const flow = providerId === "claude" ? import_subscriptions8.claudeOAuth : import_subscriptions8.geminiOAuth;
|
|
3911
4862
|
const { authUrl, codeVerifier, state } = flow.generateAuthParams();
|
|
3912
4863
|
const sessionId = deps.oauthSessions.put({ providerId, codeVerifier, state });
|
|
3913
4864
|
return { status: 200, body: { authUrl, sessionId } };
|
|
3914
4865
|
}
|
|
3915
4866
|
async function handleOAuthComplete(providerId, body, deps) {
|
|
3916
4867
|
if (!OAUTH_HTTP_PROVIDERS.has(providerId)) {
|
|
3917
|
-
return
|
|
4868
|
+
return err5(400, `oauth not available for provider '${providerId}'`);
|
|
3918
4869
|
}
|
|
3919
4870
|
const sessionId = typeof body["sessionId"] === "string" ? body["sessionId"] : "";
|
|
3920
4871
|
const rawCode = typeof body["code"] === "string" ? body["code"] : "";
|
|
3921
|
-
if (!sessionId) return
|
|
3922
|
-
if (!rawCode) return
|
|
4872
|
+
if (!sessionId) return err5(400, "oauth complete requires { sessionId }");
|
|
4873
|
+
if (!rawCode) return err5(400, "oauth complete requires { code }");
|
|
3923
4874
|
const session = deps.oauthSessions.peek(sessionId);
|
|
3924
|
-
if (!session) return
|
|
4875
|
+
if (!session) return err5(410, "oauth session is unknown, expired, or already used");
|
|
3925
4876
|
if (session.providerId !== providerId) {
|
|
3926
|
-
return
|
|
4877
|
+
return err5(400, `oauth session does not match provider '${providerId}'`);
|
|
3927
4878
|
}
|
|
3928
4879
|
let code = rawCode.trim();
|
|
3929
4880
|
if (providerId === "claude") {
|
|
3930
4881
|
const [splitCode, pastedState] = code.split("#");
|
|
3931
|
-
if (!splitCode) return
|
|
4882
|
+
if (!splitCode) return err5(400, "no authorization code was provided");
|
|
3932
4883
|
if (pastedState && pastedState !== session.state) {
|
|
3933
|
-
return
|
|
4884
|
+
return err5(400, "oauth state did not match (possible CSRF) \u2014 aborting");
|
|
3934
4885
|
}
|
|
3935
4886
|
code = splitCode;
|
|
3936
4887
|
}
|
|
@@ -3940,7 +4891,7 @@ async function handleOAuthComplete(providerId, body, deps) {
|
|
|
3940
4891
|
block = providerId === "claude" ? await exchangeClaude(code, session.codeVerifier, session.state, exchangeFetch) : await exchangeGemini(code, session.codeVerifier, exchangeFetch);
|
|
3941
4892
|
} catch (exchangeError) {
|
|
3942
4893
|
const reason = exchangeError instanceof Error ? exchangeError.message : "token exchange failed";
|
|
3943
|
-
return
|
|
4894
|
+
return err5(502, `oauth token exchange failed for '${providerId}': ${reason}`);
|
|
3944
4895
|
}
|
|
3945
4896
|
deps.oauthSessions.consume(sessionId);
|
|
3946
4897
|
const label = typeof body["label"] === "string" && body["label"].trim() ? body["label"].trim() : void 0;
|
|
@@ -3949,7 +4900,7 @@ async function handleOAuthComplete(providerId, body, deps) {
|
|
|
3949
4900
|
return { status: 200, body: status ? { account: status } : { ok: true } };
|
|
3950
4901
|
}
|
|
3951
4902
|
async function exchangeClaude(code, codeVerifier, state, exchangeFetch) {
|
|
3952
|
-
const result = await
|
|
4903
|
+
const result = await import_subscriptions8.claudeOAuth.exchangeCodeForTokens(
|
|
3953
4904
|
{ authorizationCode: code, codeVerifier, state },
|
|
3954
4905
|
exchangeFetch
|
|
3955
4906
|
);
|
|
@@ -3965,7 +4916,7 @@ async function exchangeClaude(code, codeVerifier, state, exchangeFetch) {
|
|
|
3965
4916
|
};
|
|
3966
4917
|
}
|
|
3967
4918
|
async function exchangeGemini(code, codeVerifier, exchangeFetch) {
|
|
3968
|
-
const result = await
|
|
4919
|
+
const result = await import_subscriptions8.geminiOAuth.exchangeCodeForTokens(code, codeVerifier, exchangeFetch);
|
|
3969
4920
|
const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
|
|
3970
4921
|
return {
|
|
3971
4922
|
authMethod: "oauth",
|
|
@@ -4270,8 +5221,8 @@ function errBody(message) {
|
|
|
4270
5221
|
return { error: { type: "admin_api_error", message } };
|
|
4271
5222
|
}
|
|
4272
5223
|
var defaultCommandRunner = (command) => new Promise((resolve10) => {
|
|
4273
|
-
(0, import_node_child_process.exec)(command, { timeout: 18e4 }, (
|
|
4274
|
-
if (
|
|
5224
|
+
(0, import_node_child_process.exec)(command, { timeout: 18e4 }, (err8, _stdout, stderr) => {
|
|
5225
|
+
if (err8) resolve10({ ok: false, error: stderr.trim() || err8.message });
|
|
4275
5226
|
else resolve10({ ok: true });
|
|
4276
5227
|
});
|
|
4277
5228
|
});
|
|
@@ -4317,8 +5268,8 @@ async function handleCliLaunch(cli, body, ctx) {
|
|
|
4317
5268
|
providerId: typeof body["providerId"] === "string" ? body["providerId"] : void 0,
|
|
4318
5269
|
model: typeof body["model"] === "string" ? body["model"] : void 0
|
|
4319
5270
|
});
|
|
4320
|
-
} catch (
|
|
4321
|
-
return { status: 400, body: errBody(
|
|
5271
|
+
} catch (err8) {
|
|
5272
|
+
return { status: 400, body: errBody(err8 instanceof Error ? err8.message : "no launch target") };
|
|
4322
5273
|
}
|
|
4323
5274
|
const id = (0, import_node_crypto7.randomUUID)();
|
|
4324
5275
|
let leaseId2;
|
|
@@ -4346,9 +5297,9 @@ async function handleCliLaunch(cli, body, ctx) {
|
|
|
4346
5297
|
} else {
|
|
4347
5298
|
launch = await buildLaunchEnv(cli, ctx.llmConfig, target);
|
|
4348
5299
|
}
|
|
4349
|
-
} catch (
|
|
4350
|
-
const status =
|
|
4351
|
-
return { status, body: errBody(
|
|
5300
|
+
} catch (err8) {
|
|
5301
|
+
const status = err8 instanceof import_provider_proxy2.RouteLeaseError ? err8.status : 400;
|
|
5302
|
+
return { status, body: errBody(err8 instanceof Error ? err8.message : "failed to build launch env") };
|
|
4352
5303
|
}
|
|
4353
5304
|
const cwd = typeof body["cwd"] === "string" && body["cwd"].trim() ? body["cwd"].trim() : void 0;
|
|
4354
5305
|
const opener = ctx.opener ?? defaultTerminalOpener;
|
|
@@ -4376,9 +5327,9 @@ async function handleCliLaunch(cli, body, ctx) {
|
|
|
4376
5327
|
onFailure: onSessionEnd
|
|
4377
5328
|
});
|
|
4378
5329
|
if (cleanup) openerCleanup = cleanup;
|
|
4379
|
-
} catch (
|
|
5330
|
+
} catch (err8) {
|
|
4380
5331
|
onSessionEnd();
|
|
4381
|
-
return { status: 500, body: errBody(
|
|
5332
|
+
return { status: 500, body: errBody(err8 instanceof Error ? err8.message : "failed to open terminal") };
|
|
4382
5333
|
}
|
|
4383
5334
|
if (ended) {
|
|
4384
5335
|
openerCleanup?.();
|
|
@@ -4619,7 +5570,7 @@ function classifySearchFailure(stage, code) {
|
|
|
4619
5570
|
}
|
|
4620
5571
|
|
|
4621
5572
|
// src/search/SearchAssembly.ts
|
|
4622
|
-
var
|
|
5573
|
+
var import_upstreamFetch9 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
4623
5574
|
var import_search = require("@omnicross/core/search");
|
|
4624
5575
|
var import_api2 = require("@omnicross/core/search/api");
|
|
4625
5576
|
var import_http2 = require("@omnicross/core/search/http");
|
|
@@ -4637,7 +5588,7 @@ function searchPolicyFrom(config) {
|
|
|
4637
5588
|
};
|
|
4638
5589
|
}
|
|
4639
5590
|
function resolveSearchUpstreamDispatcher(url) {
|
|
4640
|
-
return (0,
|
|
5591
|
+
return (0, import_upstreamFetch9.resolveUpstreamDispatcher)({ url });
|
|
4641
5592
|
}
|
|
4642
5593
|
var searchUpstreamProxyConfig = createUpstreamProxyResolver();
|
|
4643
5594
|
function resolveSearchUpstreamProxyConfig(url) {
|
|
@@ -4919,7 +5870,7 @@ async function handleSearchQuery(req, res, deps) {
|
|
|
4919
5870
|
// src/admin/searchAdminView.ts
|
|
4920
5871
|
var API_KEY_PROVIDERS = /* @__PURE__ */ new Set(["tavily", "jina", "zhipu", "z.ai"]);
|
|
4921
5872
|
var BASIC_AUTH_PROVIDERS = /* @__PURE__ */ new Set(["searxng"]);
|
|
4922
|
-
function
|
|
5873
|
+
function isRecord5(value) {
|
|
4923
5874
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
4924
5875
|
}
|
|
4925
5876
|
function redactSearchServerConfig(search) {
|
|
@@ -4969,13 +5920,13 @@ function resolveSecretField(entry, field, stored) {
|
|
|
4969
5920
|
else delete entry[field];
|
|
4970
5921
|
}
|
|
4971
5922
|
function preserveSearchSecrets(incoming, current) {
|
|
4972
|
-
if (!
|
|
5923
|
+
if (!isRecord5(incoming)) return incoming;
|
|
4973
5924
|
const section = { ...incoming };
|
|
4974
5925
|
const providersValue = section["providers"];
|
|
4975
|
-
if (!
|
|
5926
|
+
if (!isRecord5(providersValue)) return section;
|
|
4976
5927
|
const providers = {};
|
|
4977
5928
|
for (const [id, entryValue] of Object.entries(providersValue)) {
|
|
4978
|
-
if (!
|
|
5929
|
+
if (!isRecord5(entryValue)) {
|
|
4979
5930
|
providers[id] = entryValue;
|
|
4980
5931
|
continue;
|
|
4981
5932
|
}
|
|
@@ -5053,7 +6004,7 @@ function parseKeyPolicyBody(body) {
|
|
|
5053
6004
|
var ENDPOINTS = /* @__PURE__ */ new Set(["chat", "responses", "messages", "gemini"]);
|
|
5054
6005
|
var TARGET_KINDS = /* @__PURE__ */ new Set(["account", "account-group", "account-pool", "provider"]);
|
|
5055
6006
|
var FALLBACKS = /* @__PURE__ */ new Set(["next", "fail", "global"]);
|
|
5056
|
-
function
|
|
6007
|
+
function isRecord6(value) {
|
|
5057
6008
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
5058
6009
|
}
|
|
5059
6010
|
function nonBlank(value) {
|
|
@@ -5073,7 +6024,7 @@ function validateGatewayBindingsSegment(patch) {
|
|
|
5073
6024
|
const ids = /* @__PURE__ */ new Set();
|
|
5074
6025
|
raw.forEach((entry, index) => {
|
|
5075
6026
|
const path2 = `bindings[${index}]`;
|
|
5076
|
-
if (!
|
|
6027
|
+
if (!isRecord6(entry)) {
|
|
5077
6028
|
errors.push(`${path2} must be an object`);
|
|
5078
6029
|
return;
|
|
5079
6030
|
}
|
|
@@ -5102,12 +6053,12 @@ function validateGatewayBindingsSegment(patch) {
|
|
|
5102
6053
|
} else if (entry.modelMappings.length > 100) {
|
|
5103
6054
|
errors.push(`${path2}.modelMappings cannot contain more than 100 entries`);
|
|
5104
6055
|
} else if (entry.modelMappings.some(
|
|
5105
|
-
(mapping) => !
|
|
6056
|
+
(mapping) => !isRecord6(mapping) || !nonBlank(mapping.source) || !nonBlank(mapping.target)
|
|
5106
6057
|
)) {
|
|
5107
6058
|
errors.push(`${path2}.modelMappings must contain non-empty source and target strings`);
|
|
5108
6059
|
}
|
|
5109
6060
|
}
|
|
5110
|
-
if (!
|
|
6061
|
+
if (!isRecord6(entry.target) || !TARGET_KINDS.has(String(entry.target.kind))) {
|
|
5111
6062
|
errors.push(`${path2}.target is invalid`);
|
|
5112
6063
|
} else {
|
|
5113
6064
|
if (!nonBlank(entry.target.providerId)) errors.push(`${path2}.target.providerId is required`);
|
|
@@ -5122,7 +6073,7 @@ function validateGatewayBindingsSegment(patch) {
|
|
|
5122
6073
|
}
|
|
5123
6074
|
}
|
|
5124
6075
|
if (entry.modelMap !== void 0) {
|
|
5125
|
-
if (!
|
|
6076
|
+
if (!isRecord6(entry.modelMap) || Object.values(entry.modelMap).some((value) => typeof value !== "string")) {
|
|
5126
6077
|
errors.push(`${path2}.modelMap must contain string values`);
|
|
5127
6078
|
}
|
|
5128
6079
|
}
|
|
@@ -5421,7 +6372,9 @@ var PROVIDER_KEYS = {
|
|
|
5421
6372
|
accounts: "opencodegoAccounts",
|
|
5422
6373
|
active: "activeOpencodegoAccountId"
|
|
5423
6374
|
},
|
|
5424
|
-
kimi: { block: "kimi", accounts: "kimiAccounts", active: "activeKimiAccountId" }
|
|
6375
|
+
kimi: { block: "kimi", accounts: "kimiAccounts", active: "activeKimiAccountId" },
|
|
6376
|
+
grok: { block: "grok", accounts: "grokAccounts", active: "activeGrokAccountId" },
|
|
6377
|
+
copilot: { block: "copilot", accounts: "copilotAccounts", active: "activeCopilotAccountId" }
|
|
5425
6378
|
};
|
|
5426
6379
|
function clone(value) {
|
|
5427
6380
|
return JSON.parse(JSON.stringify(value));
|
|
@@ -5943,7 +6896,7 @@ async function applyImport(packString, passphrase, mode, deps, parseProviderInpu
|
|
|
5943
6896
|
}
|
|
5944
6897
|
|
|
5945
6898
|
// src/admin/adminMigration.ts
|
|
5946
|
-
function
|
|
6899
|
+
function err6(status, message) {
|
|
5947
6900
|
return { status, body: { error: { type: "admin_api_error", message } } };
|
|
5948
6901
|
}
|
|
5949
6902
|
async function handleExport(body, deps) {
|
|
@@ -5953,30 +6906,30 @@ async function handleExport(body, deps) {
|
|
|
5953
6906
|
return { status: 200, body: { pack, version: BUNDLE_VERSION } };
|
|
5954
6907
|
} catch (error) {
|
|
5955
6908
|
if (error instanceof WeakPassphraseError) {
|
|
5956
|
-
return
|
|
6909
|
+
return err6(400, error.message);
|
|
5957
6910
|
}
|
|
5958
|
-
return
|
|
6911
|
+
return err6(500, "failed to build the migration pack");
|
|
5959
6912
|
}
|
|
5960
6913
|
}
|
|
5961
6914
|
async function handleImport(body, deps) {
|
|
5962
6915
|
const blob = typeof body["blob"] === "string" ? body["blob"] : "";
|
|
5963
6916
|
const passphrase = typeof body["passphrase"] === "string" ? body["passphrase"] : "";
|
|
5964
6917
|
const mode = body["mode"] === "overwrite" ? "overwrite" : "merge";
|
|
5965
|
-
if (!blob) return
|
|
6918
|
+
if (!blob) return err6(400, "import requires { blob }");
|
|
5966
6919
|
try {
|
|
5967
6920
|
const counts = await applyImport(blob, passphrase, mode, deps, deps.parseProviderInput);
|
|
5968
6921
|
return { status: 200, body: counts };
|
|
5969
6922
|
} catch (error) {
|
|
5970
6923
|
if (error instanceof WeakPassphraseError) {
|
|
5971
|
-
return
|
|
6924
|
+
return err6(400, error.message);
|
|
5972
6925
|
}
|
|
5973
|
-
return
|
|
6926
|
+
return err6(400, error instanceof Error ? error.message : "import failed");
|
|
5974
6927
|
}
|
|
5975
6928
|
}
|
|
5976
6929
|
|
|
5977
6930
|
// src/admin/usagePricing.ts
|
|
5978
6931
|
var import_usage = require("@omnicross/core/usage");
|
|
5979
|
-
var
|
|
6932
|
+
var err7 = (status, message) => ({
|
|
5980
6933
|
status,
|
|
5981
6934
|
body: { error: { type: "admin_api_error", message } }
|
|
5982
6935
|
});
|
|
@@ -5989,7 +6942,7 @@ function parseRange(query2) {
|
|
|
5989
6942
|
const startTs = parseFiniteInt(query2.get("startTs"));
|
|
5990
6943
|
const endTs = parseFiniteInt(query2.get("endTs"));
|
|
5991
6944
|
if (startTs === null || endTs === null) {
|
|
5992
|
-
return
|
|
6945
|
+
return err7(400, "startTs and endTs are required finite-integer unix-millis query params");
|
|
5993
6946
|
}
|
|
5994
6947
|
return { startTs, endTs };
|
|
5995
6948
|
}
|
|
@@ -6014,14 +6967,14 @@ async function handleUsageGet(view, query2, deps) {
|
|
|
6014
6967
|
case "timeseries": {
|
|
6015
6968
|
const bucket = query2.get("bucket");
|
|
6016
6969
|
if (bucket !== "hour" && bucket !== "day" && bucket !== "month") {
|
|
6017
|
-
return
|
|
6970
|
+
return err7(400, "bucket must be one of 'hour', 'day', 'month'");
|
|
6018
6971
|
}
|
|
6019
6972
|
const now = Date.now();
|
|
6020
6973
|
const clamped = { startTs: range.startTs, endTs: Math.min(range.endTs, now) };
|
|
6021
6974
|
if (clamped.startTs < clamped.endTs) {
|
|
6022
6975
|
const projected = Math.ceil((clamped.endTs - clamped.startTs) / BUCKET_SPAN_MS[bucket]) + 1;
|
|
6023
6976
|
if (projected > MAX_TIMESERIES_BUCKETS) {
|
|
6024
|
-
return
|
|
6977
|
+
return err7(
|
|
6025
6978
|
400,
|
|
6026
6979
|
`requested range projects ~${projected} '${bucket}' buckets (max ${MAX_TIMESERIES_BUCKETS}); narrow the range or use a coarser bucket`
|
|
6027
6980
|
);
|
|
@@ -6044,7 +6997,7 @@ async function handleUsageGet(view, query2, deps) {
|
|
|
6044
6997
|
};
|
|
6045
6998
|
}
|
|
6046
6999
|
default:
|
|
6047
|
-
return
|
|
7000
|
+
return err7(404, `unknown usage view '${view ?? ""}'`);
|
|
6048
7001
|
}
|
|
6049
7002
|
}
|
|
6050
7003
|
function poolKeyLabels(cfg) {
|
|
@@ -6093,7 +7046,7 @@ async function handlePricingList(deps) {
|
|
|
6093
7046
|
async function handlePricingUpsert(body, deps) {
|
|
6094
7047
|
const input = parsePricingEntryInput(body);
|
|
6095
7048
|
if (!input) {
|
|
6096
|
-
return
|
|
7049
|
+
return err7(400, "invalid pricing entry (providerId, modelId, finite numeric inputPricePer1m/outputPricePer1m required)");
|
|
6097
7050
|
}
|
|
6098
7051
|
const entry = await deps.pricingEngine.upsertManual(input);
|
|
6099
7052
|
return { status: 200, body: { entry } };
|
|
@@ -6102,7 +7055,7 @@ async function handlePricingDelete(query2, deps) {
|
|
|
6102
7055
|
const providerId = query2.get("providerId")?.trim() ?? "";
|
|
6103
7056
|
const modelId = query2.get("modelId")?.trim() ?? "";
|
|
6104
7057
|
if (!providerId || !modelId) {
|
|
6105
|
-
return
|
|
7058
|
+
return err7(400, "delete requires providerId and modelId query params");
|
|
6106
7059
|
}
|
|
6107
7060
|
const deleted = await deps.pricingStore.delete(providerId, modelId);
|
|
6108
7061
|
if (deleted) await deps.pricingEngine.invalidateCache();
|
|
@@ -6122,13 +7075,13 @@ async function handlePricingFetchLatest(deps) {
|
|
|
6122
7075
|
}
|
|
6123
7076
|
};
|
|
6124
7077
|
} catch (e) {
|
|
6125
|
-
return
|
|
7078
|
+
return err7(502, `pricing-source fetch failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
6126
7079
|
}
|
|
6127
7080
|
}
|
|
6128
7081
|
async function handlePricingResolveConflicts(body, deps) {
|
|
6129
7082
|
const raw = body["resolutions"];
|
|
6130
7083
|
if (!Array.isArray(raw)) {
|
|
6131
|
-
return
|
|
7084
|
+
return err7(400, "resolve-conflicts requires { resolutions: [...] }");
|
|
6132
7085
|
}
|
|
6133
7086
|
const currentRows = await deps.pricingStore.getAll();
|
|
6134
7087
|
const userEditedKeys = new Set(
|
|
@@ -6138,21 +7091,21 @@ async function handlePricingResolveConflicts(body, deps) {
|
|
|
6138
7091
|
const pendingIncoming = /* @__PURE__ */ new Map();
|
|
6139
7092
|
let staleCount = 0;
|
|
6140
7093
|
for (const item of raw) {
|
|
6141
|
-
if (!item || typeof item !== "object") return
|
|
7094
|
+
if (!item || typeof item !== "object") return err7(400, "invalid resolution entry");
|
|
6142
7095
|
const r = item;
|
|
6143
7096
|
const action = r["action"];
|
|
6144
7097
|
if (action !== "overwrite" && action !== "skip") {
|
|
6145
|
-
return
|
|
7098
|
+
return err7(400, "resolution action must be 'overwrite' or 'skip'");
|
|
6146
7099
|
}
|
|
6147
7100
|
const providerId = typeof r["providerId"] === "string" && r["providerId"].trim() ? r["providerId"].trim() : "";
|
|
6148
7101
|
const modelId = typeof r["modelId"] === "string" && r["modelId"].trim() ? r["modelId"].trim() : "";
|
|
6149
7102
|
if (!providerId || !modelId) {
|
|
6150
|
-
return
|
|
7103
|
+
return err7(400, "each resolution requires top-level providerId and modelId");
|
|
6151
7104
|
}
|
|
6152
7105
|
const incoming = parsePricingEntryInput(r["incoming"]);
|
|
6153
|
-
if (!incoming) return
|
|
7106
|
+
if (!incoming) return err7(400, "each resolution must echo a valid incoming pricing entry");
|
|
6154
7107
|
if (incoming.providerId !== providerId || incoming.modelId !== modelId) {
|
|
6155
|
-
return
|
|
7108
|
+
return err7(400, "resolution providerId/modelId must match the echoed incoming entry");
|
|
6156
7109
|
}
|
|
6157
7110
|
const key = `${providerId}::${modelId}`;
|
|
6158
7111
|
if (action === "overwrite" && !userEditedKeys.has(key)) {
|
|
@@ -6197,7 +7150,7 @@ function query(req) {
|
|
|
6197
7150
|
}
|
|
6198
7151
|
function allowanceProvider(value) {
|
|
6199
7152
|
if (!value) return void 0;
|
|
6200
|
-
return value === "claude" || value === "codex" || value === "kimi" || value === "opencodego" ? value : null;
|
|
7153
|
+
return value === "claude" || value === "codex" || value === "kimi" || value === "opencodego" || value === "grok" || value === "copilot" || value === "gemini" ? value : null;
|
|
6201
7154
|
}
|
|
6202
7155
|
async function handleAccountAllowanceApi(req, res, method, rest, service) {
|
|
6203
7156
|
if (!service) return writeError2(res, 501, "account allowance service is not available");
|
|
@@ -6212,7 +7165,7 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
|
|
|
6212
7165
|
const pathProvider = rest.length >= 2 ? rest[0] : null;
|
|
6213
7166
|
const providerId = allowanceProvider(pathProvider ?? params.get("providerId") ?? params.get("provider"));
|
|
6214
7167
|
if (providerId === null) {
|
|
6215
|
-
return writeError2(res, 400, "providerId must be claude, codex, kimi, or
|
|
7168
|
+
return writeError2(res, 400, "providerId must be claude, codex, kimi, opencodego, grok, copilot, or gemini");
|
|
6216
7169
|
}
|
|
6217
7170
|
const accountId = rest.length >= 2 ? rest[1] : params.get("accountId") ?? void 0;
|
|
6218
7171
|
const allowances = await service.list({ providerId, accountId });
|
|
@@ -6254,6 +7207,36 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
|
|
|
6254
7207
|
}
|
|
6255
7208
|
return writeJson3(res, 200, { allowances: allowances2 });
|
|
6256
7209
|
}
|
|
7210
|
+
if (requestedProvider === "copilot") {
|
|
7211
|
+
if (!service.refreshCopilot) {
|
|
7212
|
+
return writeError2(res, 501, "copilot allowance refresh is not available");
|
|
7213
|
+
}
|
|
7214
|
+
const allowances2 = await service.refreshCopilot(accountId);
|
|
7215
|
+
if (accountId && allowances2.length === 0) {
|
|
7216
|
+
return writeError2(res, 404, `Copilot account '${accountId}' not found`);
|
|
7217
|
+
}
|
|
7218
|
+
return writeJson3(res, 200, { allowances: allowances2 });
|
|
7219
|
+
}
|
|
7220
|
+
if (requestedProvider === "grok") {
|
|
7221
|
+
if (!service.refreshGrok) {
|
|
7222
|
+
return writeError2(res, 501, "grok allowance refresh is not available");
|
|
7223
|
+
}
|
|
7224
|
+
const allowances2 = await service.refreshGrok(accountId);
|
|
7225
|
+
if (accountId && allowances2.length === 0) {
|
|
7226
|
+
return writeError2(res, 404, `Grok account '${accountId}' not found`);
|
|
7227
|
+
}
|
|
7228
|
+
return writeJson3(res, 200, { allowances: allowances2 });
|
|
7229
|
+
}
|
|
7230
|
+
if (requestedProvider === "gemini") {
|
|
7231
|
+
if (!service.refreshGemini) {
|
|
7232
|
+
return writeError2(res, 501, "gemini allowance refresh is not available");
|
|
7233
|
+
}
|
|
7234
|
+
const allowances2 = await service.refreshGemini(accountId);
|
|
7235
|
+
if (accountId && allowances2.length === 0) {
|
|
7236
|
+
return writeError2(res, 404, `Gemini account '${accountId}' not found`);
|
|
7237
|
+
}
|
|
7238
|
+
return writeJson3(res, 200, { allowances: allowances2 });
|
|
7239
|
+
}
|
|
6257
7240
|
const allowances = await service.refreshClaude(accountId);
|
|
6258
7241
|
if (accountId && allowances.length === 0) {
|
|
6259
7242
|
return writeError2(res, 404, `Claude account '${accountId}' not found`);
|
|
@@ -6352,6 +7335,9 @@ function toProviderView(row) {
|
|
|
6352
7335
|
apiVersion: row.apiVersion,
|
|
6353
7336
|
maxConcurrency: row.maxConcurrency,
|
|
6354
7337
|
modelsEndpoint: row.modelsEndpoint,
|
|
7338
|
+
// Static extra headers round-trip VERBATIM (non-secret identity values;
|
|
7339
|
+
// auth/content names were already dropped at the write/load gate).
|
|
7340
|
+
extraHeaders: row.extraHeaders,
|
|
6355
7341
|
// app-parity child 5: transformer config round-trips VERBATIM (non-secret —
|
|
6356
7342
|
// transform-rule names + options, no key material; absent stays absent).
|
|
6357
7343
|
transformer: row.transformer,
|
|
@@ -6421,8 +7407,8 @@ async function handleAdminApi(req, res, path2, deps) {
|
|
|
6421
7407
|
default:
|
|
6422
7408
|
return writeJsonError(res, 404, `unknown admin resource '${resource}'`);
|
|
6423
7409
|
}
|
|
6424
|
-
} catch (
|
|
6425
|
-
writeJsonError(res, 500,
|
|
7410
|
+
} catch (err8) {
|
|
7411
|
+
writeJsonError(res, 500, err8 instanceof Error ? err8.message : String(err8));
|
|
6426
7412
|
}
|
|
6427
7413
|
}
|
|
6428
7414
|
function requestQuery(req) {
|
|
@@ -6580,6 +7566,9 @@ async function handleProviderReorder(req, res, cfg, deps) {
|
|
|
6580
7566
|
persistProviders(cfg, deps);
|
|
6581
7567
|
return writeJson4(res, 200, { ok: true, providers: cfg.providers.map(toProviderView) });
|
|
6582
7568
|
}
|
|
7569
|
+
function expandRowExtraHeaders(row) {
|
|
7570
|
+
return (0, import_core3.mergeExtraHeaders)({}, row.extraHeaders);
|
|
7571
|
+
}
|
|
6583
7572
|
async function handleDiscoverModels(res, id, cfg) {
|
|
6584
7573
|
if (!id) return writeJsonError(res, 400, "provider id required in path");
|
|
6585
7574
|
const row = cfg.providers.find((p) => p.id === id);
|
|
@@ -6593,7 +7582,8 @@ async function handleDiscoverModels(res, id, cfg) {
|
|
|
6593
7582
|
try {
|
|
6594
7583
|
const headers = { Accept: "application/json" };
|
|
6595
7584
|
if (resolvedKey) headers["Authorization"] = `Bearer ${resolvedKey}`;
|
|
6596
|
-
|
|
7585
|
+
Object.assign(headers, expandRowExtraHeaders(row));
|
|
7586
|
+
const response = await (0, import_upstreamFetch10.fetchUpstream)(url, { method: "GET", headers }, { providerId: "byo" });
|
|
6597
7587
|
if (!response.ok) {
|
|
6598
7588
|
const text = await response.text().catch(() => "");
|
|
6599
7589
|
let message = text.slice(0, 300);
|
|
@@ -6610,8 +7600,8 @@ async function handleDiscoverModels(res, id, cfg) {
|
|
|
6610
7600
|
const data = await response.json();
|
|
6611
7601
|
const models = Array.isArray(data?.data) ? data.data.map((m) => typeof m?.id === "string" ? m.id : "").filter((m) => m.length > 0) : [];
|
|
6612
7602
|
return writeJson4(res, 200, { models });
|
|
6613
|
-
} catch (
|
|
6614
|
-
const message =
|
|
7603
|
+
} catch (err8) {
|
|
7604
|
+
const message = err8 instanceof Error ? err8.message : String(err8);
|
|
6615
7605
|
return writeJson4(res, 200, { models: [], error: `discovery failed: ${message}` });
|
|
6616
7606
|
}
|
|
6617
7607
|
}
|
|
@@ -6650,9 +7640,10 @@ async function handleTestModel(req, res, id, cfg) {
|
|
|
6650
7640
|
messages: [{ role: "user", content: prompt }]
|
|
6651
7641
|
};
|
|
6652
7642
|
}
|
|
7643
|
+
Object.assign(headers, expandRowExtraHeaders(row));
|
|
6653
7644
|
const startedAt = Date.now();
|
|
6654
7645
|
try {
|
|
6655
|
-
const response = await (0,
|
|
7646
|
+
const response = await (0, import_upstreamFetch10.fetchUpstream)(
|
|
6656
7647
|
url,
|
|
6657
7648
|
{ method: "POST", headers, body: JSON.stringify(payload) },
|
|
6658
7649
|
{ providerId: "byo" }
|
|
@@ -6674,8 +7665,8 @@ async function handleTestModel(req, res, id, cfg) {
|
|
|
6674
7665
|
latencyMs,
|
|
6675
7666
|
sample: extractSampleText(text, row.apiFormat)
|
|
6676
7667
|
});
|
|
6677
|
-
} catch (
|
|
6678
|
-
const message =
|
|
7668
|
+
} catch (err8) {
|
|
7669
|
+
const message = err8 instanceof Error ? err8.message : String(err8);
|
|
6679
7670
|
return writeJson4(res, 200, { ok: false, latencyMs: Date.now() - startedAt, message });
|
|
6680
7671
|
}
|
|
6681
7672
|
}
|
|
@@ -6957,6 +7948,7 @@ function parseProviderInput(body, existing) {
|
|
|
6957
7948
|
const apiVersion = typeof body["apiVersion"] === "string" && body["apiVersion"].length > 0 ? body["apiVersion"] : body["apiVersion"] === null ? void 0 : existing?.apiVersion;
|
|
6958
7949
|
const modelsEndpoint = typeof body["modelsEndpoint"] === "string" && body["modelsEndpoint"].length > 0 ? body["modelsEndpoint"] : body["modelsEndpoint"] === null ? void 0 : existing?.modelsEndpoint;
|
|
6959
7950
|
const maxConcurrency = typeof body["maxConcurrency"] === "number" && Number.isFinite(body["maxConcurrency"]) ? body["maxConcurrency"] : body["maxConcurrency"] === null ? void 0 : existing?.maxConcurrency;
|
|
7951
|
+
const extraHeaders = body["extraHeaders"] === null ? void 0 : body["extraHeaders"] === void 0 ? existing?.extraHeaders : validateExtraHeaders(body["extraHeaders"]);
|
|
6960
7952
|
const transformer = body["transformer"] === null ? void 0 : parseTransformerInput(body["transformer"], existing?.transformer);
|
|
6961
7953
|
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
7954
|
const apiModes = body["apiModes"] === null ? void 0 : parseApiModesInput(body["apiModes"], existing?.apiModes);
|
|
@@ -6982,6 +7974,7 @@ function parseProviderInput(body, existing) {
|
|
|
6982
7974
|
apiVersion,
|
|
6983
7975
|
maxConcurrency,
|
|
6984
7976
|
modelsEndpoint,
|
|
7977
|
+
extraHeaders,
|
|
6985
7978
|
transformer: migrated.transformer,
|
|
6986
7979
|
codingPlan,
|
|
6987
7980
|
apiModes,
|
|
@@ -7003,7 +7996,10 @@ function handlePresets(res, method) {
|
|
|
7003
7996
|
description: p.description,
|
|
7004
7997
|
features: p.features,
|
|
7005
7998
|
website: p.website,
|
|
7006
|
-
modelsEndpoint: p.modelsEndpoint
|
|
7999
|
+
modelsEndpoint: p.modelsEndpoint,
|
|
8000
|
+
// Static extra headers ride along so `addFromPreset` can seed them onto the
|
|
8001
|
+
// row (the write gateway re-validates via the shared allowlist).
|
|
8002
|
+
extraHeaders: p.extraHeaders
|
|
7007
8003
|
}));
|
|
7008
8004
|
return writeJson4(res, 200, { presets, excluded });
|
|
7009
8005
|
}
|
|
@@ -7485,12 +8481,12 @@ async function handleAccounts(req, res, method, rest, deps) {
|
|
|
7485
8481
|
}
|
|
7486
8482
|
return writeJson4(res, 200, { ok: true, affected: result.affected });
|
|
7487
8483
|
}
|
|
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);
|
|
8484
|
+
if (method === "GET" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot") && rest[1] === "oauth" && rest[3] === "status") {
|
|
8485
|
+
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
8486
|
return writeJson4(res, result.status, result.body);
|
|
7491
8487
|
}
|
|
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);
|
|
8488
|
+
if (method === "DELETE" && (rest[0] === "codex" || rest[0] === "kimi" || rest[0] === "grok" || rest[0] === "copilot") && rest[1] === "oauth" && rest[2]) {
|
|
8489
|
+
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
8490
|
return writeJson4(res, result.status, result.body);
|
|
7495
8491
|
}
|
|
7496
8492
|
if (method === "GET" && rest.length === 3 && rest[2] === "diagnostics") {
|
|
@@ -7551,6 +8547,15 @@ async function handleAccounts(req, res, method, rest, deps) {
|
|
|
7551
8547
|
const result2 = await handleKimiOAuthStart(deps);
|
|
7552
8548
|
return writeJson4(res, result2.status, result2.body);
|
|
7553
8549
|
}
|
|
8550
|
+
if (providerId === "grok") {
|
|
8551
|
+
const result2 = await handleGrokOAuthStart(deps);
|
|
8552
|
+
return writeJson4(res, result2.status, result2.body);
|
|
8553
|
+
}
|
|
8554
|
+
if (providerId === "copilot") {
|
|
8555
|
+
const body2 = await readJsonBody4(req);
|
|
8556
|
+
const result2 = await handleCopilotOAuthStart(deps, body2["enterpriseUrl"]);
|
|
8557
|
+
return writeJson4(res, result2.status, result2.body);
|
|
8558
|
+
}
|
|
7554
8559
|
const result = handleOAuthStart(providerId, deps);
|
|
7555
8560
|
return writeJson4(res, result.status, result.body);
|
|
7556
8561
|
}
|
|
@@ -8045,12 +9050,12 @@ async function handlePlayground(req, res, method, deps) {
|
|
|
8045
9050
|
const payload = body["body"];
|
|
8046
9051
|
const status = deps.outboundApiServer.getStatus();
|
|
8047
9052
|
if (!status.running || !status.port) return writeJsonError(res, 503, "outbound server not running");
|
|
8048
|
-
const path2 = resolvePlaygroundPath(endpoint,
|
|
9053
|
+
const path2 = resolvePlaygroundPath(endpoint, isRecord7(payload) ? payload : {});
|
|
8049
9054
|
if (!path2) return writeJsonError(res, 400, `unknown endpoint '${endpoint}'`);
|
|
8050
9055
|
const upstreamBody = typeof payload === "string" ? payload : JSON.stringify(payload ?? {});
|
|
8051
9056
|
await proxyToOutbound(res, status.port, path2, key, upstreamBody);
|
|
8052
9057
|
}
|
|
8053
|
-
function
|
|
9058
|
+
function isRecord7(v) {
|
|
8054
9059
|
return !!v && typeof v === "object" && !Array.isArray(v);
|
|
8055
9060
|
}
|
|
8056
9061
|
function proxyToOutbound(res, outboundPort, path2, key, body) {
|
|
@@ -8079,8 +9084,8 @@ function proxyToOutbound(res, outboundPort, path2, key, body) {
|
|
|
8079
9084
|
});
|
|
8080
9085
|
}
|
|
8081
9086
|
);
|
|
8082
|
-
upstream.on("error", (
|
|
8083
|
-
if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${
|
|
9087
|
+
upstream.on("error", (err8) => {
|
|
9088
|
+
if (!res.headersSent) writeJsonError(res, 502, `playground proxy failed: ${err8.message}`);
|
|
8084
9089
|
else res.end();
|
|
8085
9090
|
resolve10();
|
|
8086
9091
|
});
|
|
@@ -8186,7 +9191,7 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
|
|
|
8186
9191
|
}
|
|
8187
9192
|
|
|
8188
9193
|
// src/admin/version.ts
|
|
8189
|
-
var DAEMON_VERSION = true ? "0.
|
|
9194
|
+
var DAEMON_VERSION = true ? "0.4.1" : "0.0.0-dev";
|
|
8190
9195
|
|
|
8191
9196
|
// src/admin/AdminServer.ts
|
|
8192
9197
|
var LOOPBACK_ADDR = "127.0.0.1";
|
|
@@ -8229,13 +9234,13 @@ var AdminServer = class {
|
|
|
8229
9234
|
const server = import_node_http2.default.createServer((req, res) => {
|
|
8230
9235
|
this.onRequest(req, res);
|
|
8231
9236
|
});
|
|
8232
|
-
const onError = (
|
|
8233
|
-
if (
|
|
9237
|
+
const onError = (err8) => {
|
|
9238
|
+
if (err8.code === "EADDRINUSE" && port !== 0) {
|
|
8234
9239
|
server.removeListener("error", onError);
|
|
8235
9240
|
this.listen(bindAddr, 0).then(resolve10, reject);
|
|
8236
9241
|
return;
|
|
8237
9242
|
}
|
|
8238
|
-
reject(
|
|
9243
|
+
reject(err8);
|
|
8239
9244
|
};
|
|
8240
9245
|
server.on("error", onError);
|
|
8241
9246
|
server.listen(port, bindAddr, () => {
|
|
@@ -8253,8 +9258,8 @@ var AdminServer = class {
|
|
|
8253
9258
|
}
|
|
8254
9259
|
/** Per-request handler: auth gate (when a token is set) → routing. */
|
|
8255
9260
|
onRequest(req, res) {
|
|
8256
|
-
void this.dispatch(req, res).catch((
|
|
8257
|
-
const message =
|
|
9261
|
+
void this.dispatch(req, res).catch((err8) => {
|
|
9262
|
+
const message = err8 instanceof Error ? err8.message : String(err8);
|
|
8258
9263
|
this.deps.logger.error("[AdminServer] unhandled error:", message);
|
|
8259
9264
|
if (!res.headersSent) {
|
|
8260
9265
|
res.writeHead(500, { "Content-Type": "application/json" });
|
|
@@ -8518,18 +9523,18 @@ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal
|
|
|
8518
9523
|
return;
|
|
8519
9524
|
}
|
|
8520
9525
|
signal?.addEventListener("abort", abort, { once: true });
|
|
8521
|
-
server.on("error", (
|
|
9526
|
+
server.on("error", (err8) => {
|
|
8522
9527
|
if (settled) return;
|
|
8523
9528
|
settled = true;
|
|
8524
9529
|
clearTimeout(timer);
|
|
8525
|
-
if (
|
|
9530
|
+
if (err8.code === "EADDRINUSE") {
|
|
8526
9531
|
reject(
|
|
8527
9532
|
new Error(
|
|
8528
9533
|
`login: cannot bind ${LOOPBACK_HOST}:${LOOPBACK_PORT} (address in use) \u2014 another codex login or process is holding the port`
|
|
8529
9534
|
)
|
|
8530
9535
|
);
|
|
8531
9536
|
} else {
|
|
8532
|
-
reject(
|
|
9537
|
+
reject(err8);
|
|
8533
9538
|
}
|
|
8534
9539
|
});
|
|
8535
9540
|
const timer = setTimeout(() => {
|
|
@@ -8605,21 +9610,22 @@ function createPoolKeysLoader(getProviderRow, autoDisabled) {
|
|
|
8605
9610
|
}
|
|
8606
9611
|
|
|
8607
9612
|
// src/allowance/ProviderKeyQuotaService.ts
|
|
8608
|
-
var
|
|
9613
|
+
var import_core4 = require("@omnicross/core");
|
|
9614
|
+
var import_upstreamFetch11 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
8609
9615
|
|
|
8610
9616
|
// 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
|
|
9617
|
+
var MINUTE_MS3 = 6e4;
|
|
9618
|
+
var HOUR_MS2 = 60 * MINUTE_MS3;
|
|
9619
|
+
var DAY_MS3 = 24 * HOUR_MS2;
|
|
9620
|
+
var WEEK_MS = 7 * DAY_MS3;
|
|
9621
|
+
var MONTH_MS = 30 * DAY_MS3;
|
|
9622
|
+
function finiteNumber5(value) {
|
|
8617
9623
|
if (value === null || value === void 0 || value === "") return void 0;
|
|
8618
9624
|
const parsed = typeof value === "number" ? value : Number(value);
|
|
8619
9625
|
return Number.isFinite(parsed) && parsed >= 0 ? parsed : void 0;
|
|
8620
9626
|
}
|
|
8621
9627
|
function finitePercent4(value) {
|
|
8622
|
-
const parsed =
|
|
9628
|
+
const parsed = finiteNumber5(value);
|
|
8623
9629
|
return parsed !== void 0 && parsed <= 100 ? parsed : null;
|
|
8624
9630
|
}
|
|
8625
9631
|
function isoInstant3(value) {
|
|
@@ -8627,18 +9633,18 @@ function isoInstant3(value) {
|
|
|
8627
9633
|
const time = Date.parse(value);
|
|
8628
9634
|
if (Number.isFinite(time)) return new Date(time).toISOString();
|
|
8629
9635
|
}
|
|
8630
|
-
const numeric =
|
|
9636
|
+
const numeric = finiteNumber5(value);
|
|
8631
9637
|
if (numeric !== void 0 && numeric > 1e9) {
|
|
8632
9638
|
const ms = numeric > 1e12 ? numeric : numeric * 1e3;
|
|
8633
9639
|
return new Date(ms).toISOString();
|
|
8634
9640
|
}
|
|
8635
9641
|
return void 0;
|
|
8636
9642
|
}
|
|
8637
|
-
function
|
|
9643
|
+
function secondsUntil8(instant, now) {
|
|
8638
9644
|
if (!instant) return void 0;
|
|
8639
9645
|
return Math.max(0, Math.floor((Date.parse(instant) - now) / 1e3));
|
|
8640
9646
|
}
|
|
8641
|
-
function
|
|
9647
|
+
function isRecord8(value) {
|
|
8642
9648
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
8643
9649
|
}
|
|
8644
9650
|
function detectProviderKeyQuotaAdapter(baseUrl) {
|
|
@@ -8651,7 +9657,7 @@ function detectProviderKeyQuotaAdapter(baseUrl) {
|
|
|
8651
9657
|
}
|
|
8652
9658
|
const host = url.hostname.toLowerCase();
|
|
8653
9659
|
const path2 = url.pathname.toLowerCase();
|
|
8654
|
-
if ((host === "api.z.ai" || host === "open.bigmodel.cn") && path2.includes("/coding")) {
|
|
9660
|
+
if ((host === "api.z.ai" || host === "open.bigmodel.cn") && (path2.includes("/coding") || path2.includes("/anthropic"))) {
|
|
8655
9661
|
return "zai";
|
|
8656
9662
|
}
|
|
8657
9663
|
if ((host === "api.minimax.io" || host === "api.minimaxi.com") && // Token Plan rides the plain openai `/v1` (chat completions) surface; the
|
|
@@ -8661,6 +9667,7 @@ function detectProviderKeyQuotaAdapter(baseUrl) {
|
|
|
8661
9667
|
}
|
|
8662
9668
|
if (host === "api.code.umans.ai") return "umans";
|
|
8663
9669
|
if (host === "api.synthetic.new") return "synthetic";
|
|
9670
|
+
if (host === "api.cline.bot") return "cline-pass";
|
|
8664
9671
|
return null;
|
|
8665
9672
|
}
|
|
8666
9673
|
function providerKeyQuotaUrl(adapter, baseUrl) {
|
|
@@ -8668,6 +9675,7 @@ function providerKeyQuotaUrl(adapter, baseUrl) {
|
|
|
8668
9675
|
if (adapter === "zai") return `${origin}/api/monitor/usage/quota/limit`;
|
|
8669
9676
|
if (adapter === "minimax-token-plan") return `${origin}/v1/token_plan/remains`;
|
|
8670
9677
|
if (adapter === "umans") return `${origin}/v1/usage`;
|
|
9678
|
+
if (adapter === "cline-pass") return `${origin}/api/v1/users/me/plan/usage-limits`;
|
|
8671
9679
|
return `${origin}/v2/quotas`;
|
|
8672
9680
|
}
|
|
8673
9681
|
function providerKeyQuotaAuthHeader(adapter, key) {
|
|
@@ -8679,7 +9687,7 @@ function zaiWindowDurationMs(item) {
|
|
|
8679
9687
|
case 3:
|
|
8680
9688
|
return count * HOUR_MS2;
|
|
8681
9689
|
case 4:
|
|
8682
|
-
return count *
|
|
9690
|
+
return count * DAY_MS3;
|
|
8683
9691
|
case 5:
|
|
8684
9692
|
return count * MONTH_MS;
|
|
8685
9693
|
case 6:
|
|
@@ -8692,8 +9700,8 @@ function zaiWindowIdLabel(durationMs) {
|
|
|
8692
9700
|
if (durationMs === WEEK_MS) return { id: "seven-day", label: "7 days" };
|
|
8693
9701
|
if (durationMs === 5 * HOUR_MS2) return { id: "five-hour", label: "5 hours" };
|
|
8694
9702
|
if (durationMs === MONTH_MS) return { id: "thirty-day", label: "30 days" };
|
|
8695
|
-
if (durationMs !== void 0 && durationMs %
|
|
8696
|
-
const days = durationMs /
|
|
9703
|
+
if (durationMs !== void 0 && durationMs % DAY_MS3 === 0) {
|
|
9704
|
+
const days = durationMs / DAY_MS3;
|
|
8697
9705
|
return { id: `${days}d`, label: `${days} day${days === 1 ? "" : "s"}` };
|
|
8698
9706
|
}
|
|
8699
9707
|
if (durationMs !== void 0 && durationMs % HOUR_MS2 === 0) {
|
|
@@ -8703,23 +9711,23 @@ function zaiWindowIdLabel(durationMs) {
|
|
|
8703
9711
|
return { id: "quota", label: "Quota" };
|
|
8704
9712
|
}
|
|
8705
9713
|
function parseZaiQuotaPayload(payload, now) {
|
|
8706
|
-
if (!
|
|
8707
|
-
const data =
|
|
9714
|
+
if (!isRecord8(payload)) return null;
|
|
9715
|
+
const data = isRecord8(payload["data"]) ? payload["data"] : payload;
|
|
8708
9716
|
if (payload["success"] === false) return null;
|
|
8709
9717
|
const limits = Array.isArray(data["limits"]) ? data["limits"] : [];
|
|
8710
9718
|
const byWindow = /* @__PURE__ */ new Map();
|
|
8711
9719
|
for (const raw of limits) {
|
|
8712
|
-
if (!
|
|
9720
|
+
if (!isRecord8(raw)) continue;
|
|
8713
9721
|
const item = raw;
|
|
8714
9722
|
if (item.type === void 0) continue;
|
|
8715
9723
|
const details = raw["usageDetails"];
|
|
8716
|
-
if (Array.isArray(details) && details.some((d) =>
|
|
9724
|
+
if (Array.isArray(details) && details.some((d) => isRecord8(d) && d["modelCode"] === "zread")) {
|
|
8717
9725
|
continue;
|
|
8718
9726
|
}
|
|
8719
9727
|
const durationMs = zaiWindowDurationMs(item);
|
|
8720
9728
|
const { id, label } = zaiWindowIdLabel(durationMs);
|
|
8721
|
-
const limit =
|
|
8722
|
-
const used =
|
|
9729
|
+
const limit = finiteNumber5(item.usage);
|
|
9730
|
+
const used = finiteNumber5(item.currentValue);
|
|
8723
9731
|
const fromAbsolute = limit !== void 0 && used !== void 0 && limit > 0 ? Math.min(100, used / limit * 100) : void 0;
|
|
8724
9732
|
const fromPercentage = finitePercent4(item.percentage) ?? void 0;
|
|
8725
9733
|
const usedPercent = fromAbsolute !== void 0 ? Math.round(fromAbsolute * 10) / 10 : fromPercentage;
|
|
@@ -8730,9 +9738,9 @@ function parseZaiQuotaPayload(payload, now) {
|
|
|
8730
9738
|
label,
|
|
8731
9739
|
scope: "all",
|
|
8732
9740
|
usedPercent,
|
|
8733
|
-
...durationMs !== void 0 ? { windowMinutes: Math.round(durationMs /
|
|
9741
|
+
...durationMs !== void 0 ? { windowMinutes: Math.round(durationMs / MINUTE_MS3) } : {},
|
|
8734
9742
|
...resetsAt !== void 0 ? { resetsAt } : {},
|
|
8735
|
-
remainingSeconds:
|
|
9743
|
+
remainingSeconds: secondsUntil8(resetsAt, now),
|
|
8736
9744
|
state: "fresh"
|
|
8737
9745
|
};
|
|
8738
9746
|
const existing = byWindow.get(id);
|
|
@@ -8746,21 +9754,21 @@ function parseZaiQuotaPayload(payload, now) {
|
|
|
8746
9754
|
var MINIMAX_STATUS_EXHAUSTED = 2;
|
|
8747
9755
|
var MINIMAX_SHARED_BUCKET = "general";
|
|
8748
9756
|
function parseMiniMaxBucket(value) {
|
|
8749
|
-
if (!
|
|
9757
|
+
if (!isRecord8(value)) return null;
|
|
8750
9758
|
const modelName = typeof value["model_name"] === "string" ? value["model_name"].trim() : "";
|
|
8751
9759
|
if (!modelName) return null;
|
|
8752
9760
|
const instant = (v) => {
|
|
8753
|
-
const n =
|
|
9761
|
+
const n = finiteNumber5(v);
|
|
8754
9762
|
return n !== void 0 && n > 1e9 ? n > 1e12 ? n : n * 1e3 : void 0;
|
|
8755
9763
|
};
|
|
8756
9764
|
return {
|
|
8757
9765
|
modelName,
|
|
8758
9766
|
intervalEnd: instant(value["end_time"]),
|
|
8759
|
-
intervalRemainingPercent:
|
|
8760
|
-
intervalStatus:
|
|
9767
|
+
intervalRemainingPercent: finiteNumber5(value["current_interval_remaining_percent"]),
|
|
9768
|
+
intervalStatus: finiteNumber5(value["current_interval_status"]),
|
|
8761
9769
|
weeklyEnd: instant(value["weekly_end_time"]),
|
|
8762
|
-
weeklyRemainingPercent:
|
|
8763
|
-
weeklyStatus:
|
|
9770
|
+
weeklyRemainingPercent: finiteNumber5(value["current_weekly_remaining_percent"]),
|
|
9771
|
+
weeklyStatus: finiteNumber5(value["current_weekly_status"])
|
|
8764
9772
|
};
|
|
8765
9773
|
}
|
|
8766
9774
|
function minimaxWindow(id, label, windowMinutes, resetsAtMs, remainingPercent, status, now) {
|
|
@@ -8773,14 +9781,14 @@ function minimaxWindow(id, label, windowMinutes, resetsAtMs, remainingPercent, s
|
|
|
8773
9781
|
usedPercent,
|
|
8774
9782
|
...windowMinutes !== void 0 ? { windowMinutes } : {},
|
|
8775
9783
|
...resetsAt !== void 0 ? { resetsAt } : {},
|
|
8776
|
-
remainingSeconds:
|
|
9784
|
+
remainingSeconds: secondsUntil8(resetsAt, now),
|
|
8777
9785
|
state: usedPercent !== null ? "fresh" : "unavailable"
|
|
8778
9786
|
};
|
|
8779
9787
|
}
|
|
8780
9788
|
function parseMiniMaxTokenPlanPayload(payload, now) {
|
|
8781
|
-
if (!
|
|
9789
|
+
if (!isRecord8(payload)) return null;
|
|
8782
9790
|
const baseResp = payload["base_resp"];
|
|
8783
|
-
if (!
|
|
9791
|
+
if (!isRecord8(baseResp) || baseResp["status_code"] !== 0) return null;
|
|
8784
9792
|
const buckets = Array.isArray(payload["model_remains"]) ? payload["model_remains"] : [];
|
|
8785
9793
|
let general = null;
|
|
8786
9794
|
for (const raw of buckets) {
|
|
@@ -8804,7 +9812,7 @@ function parseMiniMaxTokenPlanPayload(payload, now) {
|
|
|
8804
9812
|
minimaxWindow(
|
|
8805
9813
|
"seven-day",
|
|
8806
9814
|
"7 days",
|
|
8807
|
-
Math.round(WEEK_MS /
|
|
9815
|
+
Math.round(WEEK_MS / MINUTE_MS3),
|
|
8808
9816
|
general.weeklyEnd,
|
|
8809
9817
|
general.weeklyRemainingPercent,
|
|
8810
9818
|
general.weeklyStatus,
|
|
@@ -8813,15 +9821,15 @@ function parseMiniMaxTokenPlanPayload(payload, now) {
|
|
|
8813
9821
|
];
|
|
8814
9822
|
}
|
|
8815
9823
|
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 =
|
|
9824
|
+
if (!isRecord8(payload)) return null;
|
|
9825
|
+
const limits = isRecord8(payload["limits"]) ? payload["limits"] : void 0;
|
|
9826
|
+
const requests = limits && isRecord8(limits["requests"]) ? limits["requests"] : void 0;
|
|
9827
|
+
const usage = isRecord8(payload["usage"]) ? payload["usage"] : void 0;
|
|
9828
|
+
const window = isRecord8(payload["window"]) ? payload["window"] : void 0;
|
|
9829
|
+
const hardCap = finiteNumber5(requests?.["hard_cap"]);
|
|
9830
|
+
const softLimit = finiteNumber5(requests?.["limit"]);
|
|
9831
|
+
const requestsInWindow = finiteNumber5(usage?.["requests_in_window"]);
|
|
9832
|
+
const weightedInWindow = finiteNumber5(usage?.["weighted_in_window"]);
|
|
8825
9833
|
const resetsAt = isoInstant3(window?.["resets_at"]);
|
|
8826
9834
|
let usedPercent = null;
|
|
8827
9835
|
if (hardCap !== void 0 && hardCap > 0 && requestsInWindow !== void 0) {
|
|
@@ -8838,19 +9846,19 @@ function parseUmansUsagePayload(payload, now) {
|
|
|
8838
9846
|
usedPercent,
|
|
8839
9847
|
windowMinutes: 5 * 60,
|
|
8840
9848
|
...resetsAt !== void 0 ? { resetsAt } : {},
|
|
8841
|
-
remainingSeconds:
|
|
9849
|
+
remainingSeconds: secondsUntil8(resetsAt, now),
|
|
8842
9850
|
state: "fresh"
|
|
8843
9851
|
}
|
|
8844
9852
|
];
|
|
8845
9853
|
}
|
|
8846
9854
|
function parseSyntheticQuotasPayload(payload, now) {
|
|
8847
|
-
if (!
|
|
8848
|
-
const fiveHour =
|
|
8849
|
-
const weekly =
|
|
9855
|
+
if (!isRecord8(payload)) return null;
|
|
9856
|
+
const fiveHour = isRecord8(payload["rollingFiveHourLimit"]) ? payload["rollingFiveHourLimit"] : void 0;
|
|
9857
|
+
const weekly = isRecord8(payload["weeklyTokenLimit"]) ? payload["weeklyTokenLimit"] : void 0;
|
|
8850
9858
|
const windows = [];
|
|
8851
9859
|
if (fiveHour) {
|
|
8852
|
-
const max =
|
|
8853
|
-
const remaining =
|
|
9860
|
+
const max = finiteNumber5(fiveHour["max"]);
|
|
9861
|
+
const remaining = finiteNumber5(fiveHour["remaining"]);
|
|
8854
9862
|
const usedPercent = max !== void 0 && max > 0 && remaining !== void 0 ? Math.round(Math.min(100, (max - remaining) / max * 100) * 10) / 10 : null;
|
|
8855
9863
|
const resetsAt = isoInstant3(fiveHour["nextTickAt"]);
|
|
8856
9864
|
windows.push({
|
|
@@ -8860,12 +9868,12 @@ function parseSyntheticQuotasPayload(payload, now) {
|
|
|
8860
9868
|
usedPercent,
|
|
8861
9869
|
windowMinutes: 5 * 60,
|
|
8862
9870
|
...resetsAt !== void 0 ? { resetsAt } : {},
|
|
8863
|
-
remainingSeconds:
|
|
9871
|
+
remainingSeconds: secondsUntil8(resetsAt, now),
|
|
8864
9872
|
state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
|
|
8865
9873
|
});
|
|
8866
9874
|
}
|
|
8867
9875
|
if (weekly) {
|
|
8868
|
-
const percentRemaining =
|
|
9876
|
+
const percentRemaining = finiteNumber5(weekly["percentRemaining"]);
|
|
8869
9877
|
const usedPercent = percentRemaining !== void 0 ? Math.round(Math.min(100, Math.max(0, 100 - percentRemaining)) * 10) / 10 : null;
|
|
8870
9878
|
const resetsAt = isoInstant3(weekly["nextRegenAt"]);
|
|
8871
9879
|
windows.push({
|
|
@@ -8875,12 +9883,42 @@ function parseSyntheticQuotasPayload(payload, now) {
|
|
|
8875
9883
|
usedPercent,
|
|
8876
9884
|
windowMinutes: 7 * 24 * 60,
|
|
8877
9885
|
...resetsAt !== void 0 ? { resetsAt } : {},
|
|
8878
|
-
remainingSeconds:
|
|
9886
|
+
remainingSeconds: secondsUntil8(resetsAt, now),
|
|
8879
9887
|
state: usedPercent !== null || resetsAt ? "fresh" : "unavailable"
|
|
8880
9888
|
});
|
|
8881
9889
|
}
|
|
8882
9890
|
return windows.length > 0 ? windows : null;
|
|
8883
9891
|
}
|
|
9892
|
+
var CLINE_WINDOW_CONFIG = {
|
|
9893
|
+
five_hour: { id: "five-hour", label: "5 hours", minutes: 5 * 60 },
|
|
9894
|
+
weekly: { id: "seven-day", label: "7 days", minutes: 7 * 24 * 60 },
|
|
9895
|
+
monthly: { id: "thirty-day", label: "30 days", minutes: 30 * 24 * 60 }
|
|
9896
|
+
};
|
|
9897
|
+
function parseClinePassUsageLimitsPayload(payload, now) {
|
|
9898
|
+
if (!isRecord8(payload)) return null;
|
|
9899
|
+
const data = isRecord8(payload["data"]) ? payload["data"] : payload;
|
|
9900
|
+
const limits = Array.isArray(data["limits"]) ? data["limits"] : [];
|
|
9901
|
+
const windows = [];
|
|
9902
|
+
for (const raw of limits) {
|
|
9903
|
+
if (!isRecord8(raw)) continue;
|
|
9904
|
+
const config = CLINE_WINDOW_CONFIG[typeof raw["type"] === "string" ? raw["type"] : ""];
|
|
9905
|
+
if (!config) continue;
|
|
9906
|
+
const usedPercent = finitePercent4(raw["percentUsed"]);
|
|
9907
|
+
if (usedPercent === null) continue;
|
|
9908
|
+
const resetsAt = isoInstant3(raw["resetsAt"]);
|
|
9909
|
+
windows.push({
|
|
9910
|
+
id: config.id,
|
|
9911
|
+
label: config.label,
|
|
9912
|
+
scope: "all",
|
|
9913
|
+
usedPercent,
|
|
9914
|
+
windowMinutes: config.minutes,
|
|
9915
|
+
...resetsAt !== void 0 ? { resetsAt } : {},
|
|
9916
|
+
remainingSeconds: secondsUntil8(resetsAt, now),
|
|
9917
|
+
state: "fresh"
|
|
9918
|
+
});
|
|
9919
|
+
}
|
|
9920
|
+
return windows.length > 0 ? windows : null;
|
|
9921
|
+
}
|
|
8884
9922
|
|
|
8885
9923
|
// src/allowance/ProviderKeyQuotaService.ts
|
|
8886
9924
|
function parseQuotaPayload(adapter, payload, now) {
|
|
@@ -8893,6 +9931,8 @@ function parseQuotaPayload(adapter, payload, now) {
|
|
|
8893
9931
|
return parseUmansUsagePayload(payload, now);
|
|
8894
9932
|
case "synthetic":
|
|
8895
9933
|
return parseSyntheticQuotasPayload(payload, now);
|
|
9934
|
+
case "cline-pass":
|
|
9935
|
+
return parseClinePassUsageLimitsPayload(payload, now);
|
|
8896
9936
|
}
|
|
8897
9937
|
}
|
|
8898
9938
|
var PROVIDER_KEY_QUOTA_CACHE_MS = 5 * 6e4;
|
|
@@ -8912,7 +9952,7 @@ function rowKeyEntries(row) {
|
|
|
8912
9952
|
return [];
|
|
8913
9953
|
}
|
|
8914
9954
|
var ProviderKeyQuotaService = class {
|
|
8915
|
-
constructor(box, fetchImpl = (url, init) => (0,
|
|
9955
|
+
constructor(box, fetchImpl = (url, init) => (0, import_upstreamFetch11.fetchUpstream)(url, init, { redactBodies: true }), now = Date.now) {
|
|
8916
9956
|
this.box = box;
|
|
8917
9957
|
this.fetchImpl = fetchImpl;
|
|
8918
9958
|
this.now = now;
|
|
@@ -8974,7 +10014,10 @@ var ProviderKeyQuotaService = class {
|
|
|
8974
10014
|
headers: {
|
|
8975
10015
|
Authorization: providerKeyQuotaAuthHeader(adapter, key),
|
|
8976
10016
|
Accept: "application/json",
|
|
8977
|
-
"Content-Type": "application/json"
|
|
10017
|
+
"Content-Type": "application/json",
|
|
10018
|
+
// The row's static identity headers ride along — the Cline usage
|
|
10019
|
+
// endpoint sits behind the SAME client-identity 403 gate as inference.
|
|
10020
|
+
...(0, import_core4.mergeExtraHeaders)({}, row.extraHeaders)
|
|
8978
10021
|
},
|
|
8979
10022
|
signal: AbortSignal.timeout(15e3)
|
|
8980
10023
|
});
|
|
@@ -9045,7 +10088,7 @@ function defaultBillingDir(configPath) {
|
|
|
9045
10088
|
// src/image-generation/ImageDoctorService.ts
|
|
9046
10089
|
var import_image_generation = require("@omnicross/core/image-generation");
|
|
9047
10090
|
var import_outbound_api7 = require("@omnicross/core/outbound-api");
|
|
9048
|
-
var
|
|
10091
|
+
var import_subscriptions9 = require("@omnicross/subscriptions");
|
|
9049
10092
|
|
|
9050
10093
|
// src/image-generation/FileCodexImageCapabilityEvidenceSource.ts
|
|
9051
10094
|
var import_node_crypto13 = require("crypto");
|
|
@@ -9483,7 +10526,7 @@ function createImageDoctorService(options) {
|
|
|
9483
10526
|
paths,
|
|
9484
10527
|
ttlMs: config.evidenceTtlMs
|
|
9485
10528
|
}));
|
|
9486
|
-
const createLiveVerifier = options.createLiveVerifier ?? ((strategy, config) => (0,
|
|
10529
|
+
const createLiveVerifier = options.createLiveVerifier ?? ((strategy, config) => (0, import_subscriptions9.createCodexImageLiveVerifier)({
|
|
9487
10530
|
authStrategy: strategy,
|
|
9488
10531
|
generationTimeoutMs: config.queue.generationTimeoutMs
|
|
9489
10532
|
}));
|
|
@@ -9845,7 +10888,7 @@ var ImageCleanupService = class {
|
|
|
9845
10888
|
var import_node_crypto16 = require("crypto");
|
|
9846
10889
|
var import_image_generation5 = require("@omnicross/core/image-generation");
|
|
9847
10890
|
var import_outbound_api8 = require("@omnicross/core/outbound-api");
|
|
9848
|
-
var
|
|
10891
|
+
var import_subscriptions10 = require("@omnicross/subscriptions");
|
|
9849
10892
|
|
|
9850
10893
|
// src/image-generation/ImageApiRuntimeResolver.ts
|
|
9851
10894
|
var import_node_crypto14 = require("crypto");
|
|
@@ -10376,7 +11419,7 @@ function createImageRuntimeGeneration(options) {
|
|
|
10376
11419
|
now: options.now ?? Date.now,
|
|
10377
11420
|
referenceStore: options.storage.referenceStore,
|
|
10378
11421
|
stateStore: options.storage.stateStore
|
|
10379
|
-
}) : (0,
|
|
11422
|
+
}) : (0, import_subscriptions10.createCodexSubscriptionImageProvider)({
|
|
10380
11423
|
authStrategy,
|
|
10381
11424
|
evidenceSource: generationEvidenceSource,
|
|
10382
11425
|
executionScheduler: scheduler,
|
|
@@ -13520,7 +14563,7 @@ var ImageRuntimeManager = class {
|
|
|
13520
14563
|
};
|
|
13521
14564
|
|
|
13522
14565
|
// src/ports/ConfigFileProviderConfigSource.ts
|
|
13523
|
-
var
|
|
14566
|
+
var import_core5 = require("@omnicross/core");
|
|
13524
14567
|
var EMPTY_CHAIN = {
|
|
13525
14568
|
providerTransformers: [],
|
|
13526
14569
|
modelTransformers: []
|
|
@@ -13545,8 +14588,8 @@ var ConfigFileProviderConfigSource = class {
|
|
|
13545
14588
|
reloadHook;
|
|
13546
14589
|
constructor(config) {
|
|
13547
14590
|
for (const p of config.providers) this.providers.set(p.id, p);
|
|
13548
|
-
this.transformerService = new
|
|
13549
|
-
void (0,
|
|
14591
|
+
this.transformerService = new import_core5.TransformerService();
|
|
14592
|
+
void (0, import_core5.registerBuiltinTransformers)(this.transformerService);
|
|
13550
14593
|
}
|
|
13551
14594
|
// ── Reload hook (key-pool design D4) ───────────────────────────────────────
|
|
13552
14595
|
/**
|
|
@@ -13567,7 +14610,7 @@ var ConfigFileProviderConfigSource = class {
|
|
|
13567
14610
|
}
|
|
13568
14611
|
/** Await the built-in transformer registration (tests await this before dispatch). */
|
|
13569
14612
|
async ready() {
|
|
13570
|
-
await (0,
|
|
14613
|
+
await (0, import_core5.registerBuiltinTransformers)(this.transformerService);
|
|
13571
14614
|
}
|
|
13572
14615
|
// ── Hot-reload seam (admin dashboard, RT3 design D6) ───────────────────────
|
|
13573
14616
|
/**
|
|
@@ -13678,6 +14721,10 @@ function toLLMProvider(row) {
|
|
|
13678
14721
|
// `parseProviderInput`), so customizations are preserved (the row value wins).
|
|
13679
14722
|
apiModes: row.apiModes,
|
|
13680
14723
|
selectedApiModeId: row.selectedApiModeId,
|
|
14724
|
+
// Static extra request headers ride along verbatim (load-guarded — no
|
|
14725
|
+
// auth/content names); core's `getProviderHeaders` merges them into every
|
|
14726
|
+
// BYO request, and the same-format relay path inherits that funnel.
|
|
14727
|
+
extraHeaders: row.extraHeaders,
|
|
13681
14728
|
// Official-Anthropic signature handling only matters for the Anthropic
|
|
13682
14729
|
// ingress (deferred → 502); leave it off for the BYO transform path.
|
|
13683
14730
|
isOfficial: false
|
|
@@ -15043,7 +16090,7 @@ function bucketLabel(bucketStartTs, bucket) {
|
|
|
15043
16090
|
|
|
15044
16091
|
// src/ports/JsonOutboundKeyDb.ts
|
|
15045
16092
|
var import_node_fs19 = require("fs");
|
|
15046
|
-
var
|
|
16093
|
+
var import_core6 = require("@omnicross/core");
|
|
15047
16094
|
|
|
15048
16095
|
// src/ports/atomicFile.ts
|
|
15049
16096
|
var import_node_crypto22 = require("crypto");
|
|
@@ -15165,7 +16212,7 @@ var JsonOutboundKeyDb = class {
|
|
|
15165
16212
|
});
|
|
15166
16213
|
}
|
|
15167
16214
|
async outboundApiKeysSetPermissions(id, permissions) {
|
|
15168
|
-
const exact = (0,
|
|
16215
|
+
const exact = (0, import_core6.validateOutboundPermissions)(permissions);
|
|
15169
16216
|
return this.mutateRow(id, (row) => {
|
|
15170
16217
|
if (row.revokedAt !== null) return false;
|
|
15171
16218
|
row.allowedEndpoints = [...exact];
|
|
@@ -15602,9 +16649,9 @@ var import_node_fs24 = require("fs");
|
|
|
15602
16649
|
var import_node_path24 = require("path");
|
|
15603
16650
|
var import_SubscriptionAccountHealth2 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
|
|
15604
16651
|
var import_AccountAllowanceScheduling3 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
|
|
15605
|
-
var
|
|
16652
|
+
var import_upstreamFetch12 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
15606
16653
|
var import_SubscriptionIdentityStore2 = require("@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore");
|
|
15607
|
-
var
|
|
16654
|
+
var import_subscriptions11 = require("@omnicross/subscriptions");
|
|
15608
16655
|
|
|
15609
16656
|
// src/ports/account-sync.ts
|
|
15610
16657
|
function viewOf(tokens) {
|
|
@@ -15752,7 +16799,7 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
15752
16799
|
* a plaintext token pair into `upstream-trace.jsonl`.
|
|
15753
16800
|
*/
|
|
15754
16801
|
buildRefreshFetch(providerId, accountId) {
|
|
15755
|
-
return this.fetchImpl ?? ((url, init) => (0,
|
|
16802
|
+
return this.fetchImpl ?? ((url, init) => (0, import_upstreamFetch12.fetchUpstream)(url, init, { providerId, accountId, redactBodies: true }));
|
|
15756
16803
|
}
|
|
15757
16804
|
/**
|
|
15758
16805
|
* In-flight refresh coalescing. OAuth refresh tokens are
|
|
@@ -15793,7 +16840,7 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
15793
16840
|
* other hot reads. Never returns token material.
|
|
15794
16841
|
*/
|
|
15795
16842
|
getAccountProxy(providerId, accountId) {
|
|
15796
|
-
if (providerId !== "claude" && providerId !== "codex" && providerId !== "gemini" && providerId !== "opencodego" && providerId !== "kimi") {
|
|
16843
|
+
if (providerId !== "claude" && providerId !== "codex" && providerId !== "gemini" && providerId !== "opencodego" && providerId !== "kimi" && providerId !== "grok" && providerId !== "copilot") {
|
|
15797
16844
|
return void 0;
|
|
15798
16845
|
}
|
|
15799
16846
|
return getAccountProxy(this.readConfig(), providerId, accountId);
|
|
@@ -15812,7 +16859,7 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
15812
16859
|
const fingerprintOn = identityStore.isEnabled();
|
|
15813
16860
|
const now = Date.now();
|
|
15814
16861
|
const out = {};
|
|
15815
|
-
for (const provider of ["claude", "codex", "gemini", "opencodego", "kimi"]) {
|
|
16862
|
+
for (const provider of ["claude", "codex", "gemini", "opencodego", "kimi", "grok", "copilot"]) {
|
|
15816
16863
|
const sanitized = sanitizeAccounts(config, provider);
|
|
15817
16864
|
if (sanitized.length === 0) continue;
|
|
15818
16865
|
for (const account of sanitized) {
|
|
@@ -15878,7 +16925,7 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
15878
16925
|
this.materializeMigration(config);
|
|
15879
16926
|
const refreshFetch = this.buildRefreshFetch("claude", capturedId);
|
|
15880
16927
|
try {
|
|
15881
|
-
const result = await
|
|
16928
|
+
const result = await import_subscriptions11.claudeOAuth.refreshAccessToken(claude.refreshToken, refreshFetch);
|
|
15882
16929
|
const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
|
|
15883
16930
|
const next = {
|
|
15884
16931
|
...claude,
|
|
@@ -15913,7 +16960,7 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
15913
16960
|
this.materializeMigration(config);
|
|
15914
16961
|
const refreshFetch = this.buildRefreshFetch("codex", capturedId);
|
|
15915
16962
|
try {
|
|
15916
|
-
const result = await
|
|
16963
|
+
const result = await import_subscriptions11.codexOAuth.refreshAccessToken(codex.refreshToken, refreshFetch);
|
|
15917
16964
|
const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
|
|
15918
16965
|
const next = {
|
|
15919
16966
|
...codex,
|
|
@@ -15951,7 +16998,7 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
15951
16998
|
this.materializeMigration(config);
|
|
15952
16999
|
const refreshFetch = this.buildRefreshFetch("gemini", capturedId);
|
|
15953
17000
|
try {
|
|
15954
|
-
const result = await
|
|
17001
|
+
const result = await import_subscriptions11.geminiOAuth.refreshAccessToken(gemini.refreshToken, refreshFetch);
|
|
15955
17002
|
const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
|
|
15956
17003
|
const next = {
|
|
15957
17004
|
...gemini,
|
|
@@ -15987,10 +17034,10 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
15987
17034
|
this.materializeMigration(config);
|
|
15988
17035
|
const refreshFetch = this.buildRefreshFetch("kimi", capturedId);
|
|
15989
17036
|
try {
|
|
15990
|
-
const result = await
|
|
17037
|
+
const result = await import_subscriptions11.kimiOAuth.refreshAccessToken(
|
|
15991
17038
|
kimi.refreshToken,
|
|
15992
17039
|
refreshFetch,
|
|
15993
|
-
|
|
17040
|
+
import_subscriptions11.kimiOAuth.kimiFingerprintHeaders(kimi.deviceId)
|
|
15994
17041
|
);
|
|
15995
17042
|
const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
|
|
15996
17043
|
const next = {
|
|
@@ -16011,6 +17058,66 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
16011
17058
|
}
|
|
16012
17059
|
});
|
|
16013
17060
|
}
|
|
17061
|
+
/**
|
|
17062
|
+
* Refresh the Grok (xAI SuperGrok) OAuth access token. The token endpoint is
|
|
17063
|
+
* resolved through OIDC discovery on every refresh (process-cached 1h by the
|
|
17064
|
+
* flow module) so a rotated endpoint document is picked up without a daemon
|
|
17065
|
+
* restart. HONEST `false` when no refresh_token.
|
|
17066
|
+
*/
|
|
17067
|
+
async refreshGrokToken() {
|
|
17068
|
+
return this.coalesce("grok:active", async () => {
|
|
17069
|
+
const config = this.readConfig();
|
|
17070
|
+
const active = getActiveAccount(config, "grok");
|
|
17071
|
+
const grok = active?.tokens;
|
|
17072
|
+
if (!active || !grok?.refreshToken) return false;
|
|
17073
|
+
const capturedId = active.id;
|
|
17074
|
+
this.materializeMigration(config);
|
|
17075
|
+
const refreshFetch = this.buildRefreshFetch("grok", capturedId);
|
|
17076
|
+
try {
|
|
17077
|
+
const tokenEndpoint = await import_subscriptions11.grokOAuth.resolveGrokTokenEndpoint(refreshFetch);
|
|
17078
|
+
const result = await import_subscriptions11.grokOAuth.refreshGrokAccessToken(grok.refreshToken, tokenEndpoint, refreshFetch);
|
|
17079
|
+
const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
|
|
17080
|
+
const next = {
|
|
17081
|
+
...grok,
|
|
17082
|
+
accessToken: result.accessToken,
|
|
17083
|
+
refreshToken: result.refreshToken,
|
|
17084
|
+
expiresAt,
|
|
17085
|
+
status: "authorized",
|
|
17086
|
+
lastRefreshedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
17087
|
+
errorMessage: void 0,
|
|
17088
|
+
syncWarning: void 0
|
|
17089
|
+
};
|
|
17090
|
+
this.writeBackById("grok", capturedId, next);
|
|
17091
|
+
return true;
|
|
17092
|
+
} catch (error) {
|
|
17093
|
+
this.markExpiredById("grok", capturedId, grok, error);
|
|
17094
|
+
return false;
|
|
17095
|
+
}
|
|
17096
|
+
});
|
|
17097
|
+
}
|
|
17098
|
+
/**
|
|
17099
|
+
* "Refresh" a GitHub Copilot token — there is nothing to refresh (ghu_
|
|
17100
|
+
* tokens are long-lived with no exchange endpoint). A call here means the
|
|
17101
|
+
* strategy saw a 401 (the token was revoked); mark the account `expired`
|
|
17102
|
+
* with a re-authenticate message and return `false` (the proxy then declines
|
|
17103
|
+
* the retry instead of looping on a dead token).
|
|
17104
|
+
*/
|
|
17105
|
+
async refreshCopilotToken() {
|
|
17106
|
+
return this.coalesce("copilot:active", async () => {
|
|
17107
|
+
const config = this.readConfig();
|
|
17108
|
+
const active = getActiveAccount(config, "copilot");
|
|
17109
|
+
const copilot = active?.tokens;
|
|
17110
|
+
if (!active || !copilot?.accessToken) return false;
|
|
17111
|
+
this.materializeMigration(config);
|
|
17112
|
+
this.markExpiredById(
|
|
17113
|
+
"copilot",
|
|
17114
|
+
active.id,
|
|
17115
|
+
copilot,
|
|
17116
|
+
new Error("GitHub Copilot tokens cannot be refreshed \u2014 re-authenticate the account")
|
|
17117
|
+
);
|
|
17118
|
+
return false;
|
|
17119
|
+
});
|
|
17120
|
+
}
|
|
16014
17121
|
/**
|
|
16015
17122
|
* Refresh a SPECIFIC managed account by id (background scheduler sweep and
|
|
16016
17123
|
* account-pool resolution). It uses only that account's stored refresh
|
|
@@ -16063,7 +17170,7 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
16063
17170
|
}
|
|
16064
17171
|
const oauth = account.tokens;
|
|
16065
17172
|
if (!oauth.accessToken) return null;
|
|
16066
|
-
if (providerId === "codex" || providerId === "gemini" || providerId === "kimi") {
|
|
17173
|
+
if (providerId === "codex" || providerId === "gemini" || providerId === "kimi" || providerId === "grok" || providerId === "copilot") {
|
|
16067
17174
|
const expiresAtMs = oauth.expiresAt ? Date.parse(oauth.expiresAt) : 0;
|
|
16068
17175
|
const expiringSoon = expiresAtMs > 0 && Date.now() >= expiresAtMs - ACCOUNT_REFRESH_LEAD_MS;
|
|
16069
17176
|
if (expiringSoon && oauth.refreshToken) {
|
|
@@ -16156,10 +17263,10 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
16156
17263
|
if (provider === "kimi") {
|
|
16157
17264
|
const account = accountId ? getAccountById(this.readConfig(), "kimi", accountId) : void 0;
|
|
16158
17265
|
const deviceId = account?.tokens?.deviceId;
|
|
16159
|
-
const r2 = await
|
|
17266
|
+
const r2 = await import_subscriptions11.kimiOAuth.refreshAccessToken(
|
|
16160
17267
|
refreshToken,
|
|
16161
17268
|
refreshFetch,
|
|
16162
|
-
|
|
17269
|
+
import_subscriptions11.kimiOAuth.kimiFingerprintHeaders(deviceId)
|
|
16163
17270
|
);
|
|
16164
17271
|
return {
|
|
16165
17272
|
accessToken: r2.accessToken,
|
|
@@ -16167,7 +17274,19 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
16167
17274
|
expiresAt: new Date(Date.now() + r2.expiresIn * 1e3).toISOString()
|
|
16168
17275
|
};
|
|
16169
17276
|
}
|
|
16170
|
-
|
|
17277
|
+
if (provider === "grok") {
|
|
17278
|
+
const tokenEndpoint = await import_subscriptions11.grokOAuth.resolveGrokTokenEndpoint(refreshFetch);
|
|
17279
|
+
const r2 = await import_subscriptions11.grokOAuth.refreshGrokAccessToken(refreshToken, tokenEndpoint, refreshFetch);
|
|
17280
|
+
return {
|
|
17281
|
+
accessToken: r2.accessToken,
|
|
17282
|
+
refreshToken: r2.refreshToken,
|
|
17283
|
+
expiresAt: new Date(Date.now() + r2.expiresIn * 1e3).toISOString()
|
|
17284
|
+
};
|
|
17285
|
+
}
|
|
17286
|
+
if (provider === "copilot") {
|
|
17287
|
+
throw new Error("GitHub Copilot tokens cannot be refreshed \u2014 re-authenticate the account");
|
|
17288
|
+
}
|
|
17289
|
+
const flow = provider === "claude" ? import_subscriptions11.claudeOAuth : provider === "codex" ? import_subscriptions11.codexOAuth : import_subscriptions11.geminiOAuth;
|
|
16171
17290
|
const r = await flow.refreshAccessToken(refreshToken, refreshFetch);
|
|
16172
17291
|
return {
|
|
16173
17292
|
accessToken: r.accessToken,
|
|
@@ -16410,7 +17529,7 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
16410
17529
|
};
|
|
16411
17530
|
|
|
16412
17531
|
// src/AccountHealthProbeScheduler.ts
|
|
16413
|
-
var
|
|
17532
|
+
var import_upstreamFetch13 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
16414
17533
|
|
|
16415
17534
|
// src/probe/CodexGenerationProbe.ts
|
|
16416
17535
|
var import_codexCliHeaders = require("@omnicross/core/provider-proxy/identity/codexCliHeaders");
|
|
@@ -16553,7 +17672,16 @@ var PROVIDER_PROBE_PLANS = {
|
|
|
16553
17672
|
// Kimi's `GET /coding/v1/usages` is a verified FREE authed GET (the allowance
|
|
16554
17673
|
// collector uses it), but the probe path also needs the fingerprint headers —
|
|
16555
17674
|
// keep the probe local until the collector covers the health surface.
|
|
16556
|
-
kimi: { kind: "local" }
|
|
17675
|
+
kimi: { kind: "local" },
|
|
17676
|
+
// Grok's billing proxy is a verified FREE authed GET (the allowance collector
|
|
17677
|
+
// uses it) but it REJECTS non-OAuth credentials and sits on a separate host
|
|
17678
|
+
// with its own product-gate header — keep the probe local, the collector
|
|
17679
|
+
// owns the health surface.
|
|
17680
|
+
grok: { kind: "local" },
|
|
17681
|
+
// The Copilot quota endpoint (copilot_internal/user) is a verified FREE
|
|
17682
|
+
// authed GET but lives on api.github.com with its own auth dialect and a
|
|
17683
|
+
// monthly-only window — the allowance collector owns the health surface.
|
|
17684
|
+
copilot: { kind: "local" }
|
|
16557
17685
|
};
|
|
16558
17686
|
function probePlanFor(providerId) {
|
|
16559
17687
|
return PROVIDER_PROBE_PLANS[providerId] ?? { kind: "local" };
|
|
@@ -16575,7 +17703,7 @@ var AccountHealthProbeScheduler = class {
|
|
|
16575
17703
|
this.logger = logger;
|
|
16576
17704
|
this.config = config;
|
|
16577
17705
|
this.now = opts.now ?? Date.now;
|
|
16578
|
-
this.fetchImpl = opts.fetchImpl ??
|
|
17706
|
+
this.fetchImpl = opts.fetchImpl ?? import_upstreamFetch13.fetchUpstream;
|
|
16579
17707
|
this.sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
16580
17708
|
this.planFor = opts.planFor ?? probePlanFor;
|
|
16581
17709
|
}
|
|
@@ -17476,7 +18604,7 @@ async function readAuditStats(auditDir, query2 = {}) {
|
|
|
17476
18604
|
}
|
|
17477
18605
|
|
|
17478
18606
|
// src/audit/AuditPruneSweeper.ts
|
|
17479
|
-
var
|
|
18607
|
+
var DAY_MS4 = 24 * 60 * 6e4;
|
|
17480
18608
|
var SWEEP_INTERVAL_MS2 = 60 * 6e4;
|
|
17481
18609
|
var ARCHIVE_BATCH = 64;
|
|
17482
18610
|
var AuditPruneSweeper = class {
|
|
@@ -17540,7 +18668,7 @@ var AuditPruneSweeper = class {
|
|
|
17540
18668
|
this.sweeping = true;
|
|
17541
18669
|
try {
|
|
17542
18670
|
if (!(0, import_node_fs27.existsSync)(this.auditDir)) return 0;
|
|
17543
|
-
const cutoff = this.todayMidnight() - (this.config.retentionDays - 1) *
|
|
18671
|
+
const cutoff = this.todayMidnight() - (this.config.retentionDays - 1) * DAY_MS4;
|
|
17544
18672
|
let removed = 0;
|
|
17545
18673
|
for (const name of (0, import_node_fs27.readdirSync)(this.auditDir)) {
|
|
17546
18674
|
const dateMs = auditFileDateMs(name);
|
|
@@ -17797,7 +18925,7 @@ async function closeAll(writers) {
|
|
|
17797
18925
|
// src/usage/UsagePruneSweeper.ts
|
|
17798
18926
|
var import_promises8 = require("fs/promises");
|
|
17799
18927
|
var import_node_path29 = require("path");
|
|
17800
|
-
var
|
|
18928
|
+
var DAY_MS5 = 24 * 60 * 6e4;
|
|
17801
18929
|
var SWEEP_INTERVAL_MS3 = 60 * 6e4;
|
|
17802
18930
|
var DEFAULT_USAGE_RETENTION_DAYS = 90;
|
|
17803
18931
|
var UsagePruneSweeper = class {
|
|
@@ -17854,7 +18982,7 @@ var UsagePruneSweeper = class {
|
|
|
17854
18982
|
this.sweeping = true;
|
|
17855
18983
|
try {
|
|
17856
18984
|
const retentionDays = this.config.retentionDays ?? DEFAULT_USAGE_RETENTION_DAYS;
|
|
17857
|
-
const cutoff = this.todayMidnight() - (retentionDays - 1) *
|
|
18985
|
+
const cutoff = this.todayMidnight() - (retentionDays - 1) * DAY_MS5;
|
|
17858
18986
|
let removed = 0;
|
|
17859
18987
|
for (const entry of await listUsageDays(this.usageDir)) {
|
|
17860
18988
|
if (!entry.hasShard) continue;
|
|
@@ -18273,7 +19401,7 @@ var AuditWriter = class {
|
|
|
18273
19401
|
var import_node_fs33 = require("fs");
|
|
18274
19402
|
var import_node_crypto24 = require("crypto");
|
|
18275
19403
|
var import_node_path33 = require("path");
|
|
18276
|
-
var
|
|
19404
|
+
var import_upstreamFetch14 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
18277
19405
|
|
|
18278
19406
|
// src/billing/billingFiles.ts
|
|
18279
19407
|
var BILLING_FILE_RE = /^billing-(\d{4})-(\d{2})-(\d{2})\.jsonl$/;
|
|
@@ -18296,7 +19424,7 @@ var BillingPublisher = class {
|
|
|
18296
19424
|
constructor(billingDir, logger, opts = {}) {
|
|
18297
19425
|
this.billingDir = billingDir;
|
|
18298
19426
|
this.logger = logger;
|
|
18299
|
-
this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0,
|
|
19427
|
+
this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch14.fetchUpstream)(url, init));
|
|
18300
19428
|
this.defer = opts.defer ?? ((fn) => setTimeout(fn, 0));
|
|
18301
19429
|
this.timeoutMs = opts.timeoutMs ?? BILLING_POST_TIMEOUT_MS;
|
|
18302
19430
|
this.now = opts.now ?? Date.now;
|
|
@@ -18546,7 +19674,7 @@ var BillingRetrySweeper = class {
|
|
|
18546
19674
|
// src/TokenRefreshScheduler.ts
|
|
18547
19675
|
var REFRESH_LEAD_MS2 = 5 * 6e4;
|
|
18548
19676
|
var SWEEP_INTERVAL_MS5 = 6e4;
|
|
18549
|
-
var OAUTH_PROVIDERS2 = ["claude", "codex", "gemini", "kimi"];
|
|
19677
|
+
var OAUTH_PROVIDERS2 = ["claude", "codex", "gemini", "kimi", "grok", "copilot"];
|
|
18550
19678
|
var TokenRefreshScheduler = class {
|
|
18551
19679
|
constructor(store, logger, intervalMs = SWEEP_INTERVAL_MS5, leadMs = REFRESH_LEAD_MS2) {
|
|
18552
19680
|
this.store = store;
|
|
@@ -18631,6 +19759,12 @@ var TokenRefreshScheduler = class {
|
|
|
18631
19759
|
return this.store.refreshGeminiToken();
|
|
18632
19760
|
case "kimi":
|
|
18633
19761
|
return this.store.refreshKimiToken();
|
|
19762
|
+
case "grok":
|
|
19763
|
+
return this.store.refreshGrokToken();
|
|
19764
|
+
// ghu_ tokens never near-expire (far-future expiresAt), so the sweep
|
|
19765
|
+
// never reaches this — the branch exists for union totality.
|
|
19766
|
+
case "copilot":
|
|
19767
|
+
return this.store.refreshCopilotToken();
|
|
18634
19768
|
}
|
|
18635
19769
|
}
|
|
18636
19770
|
};
|
|
@@ -18707,7 +19841,7 @@ function createRouteLeaseSubscriptionPreflight(credentials) {
|
|
|
18707
19841
|
|
|
18708
19842
|
// src/webhook/WebhookDispatcher.ts
|
|
18709
19843
|
var import_node_crypto25 = require("crypto");
|
|
18710
|
-
var
|
|
19844
|
+
var import_upstreamFetch15 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
18711
19845
|
var WEBHOOK_MAX_ATTEMPTS = 3;
|
|
18712
19846
|
var WEBHOOK_QUEUE_MAX = 1e3;
|
|
18713
19847
|
var WEBHOOK_SEND_TIMEOUT_MS = 1e4;
|
|
@@ -18727,7 +19861,7 @@ var WebhookDispatcher = class {
|
|
|
18727
19861
|
sleep;
|
|
18728
19862
|
now;
|
|
18729
19863
|
constructor(opts = {}) {
|
|
18730
|
-
this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0,
|
|
19864
|
+
this.fetchImpl = opts.fetchImpl ?? ((url, init) => (0, import_upstreamFetch15.fetchUpstream)(url, init));
|
|
18731
19865
|
this.logger = opts.logger;
|
|
18732
19866
|
this.maxAttempts = opts.maxAttempts ?? WEBHOOK_MAX_ATTEMPTS;
|
|
18733
19867
|
this.queueMax = opts.queueMax ?? WEBHOOK_QUEUE_MAX;
|
|
@@ -18813,8 +19947,8 @@ var WebhookDispatcher = class {
|
|
|
18813
19947
|
signal: AbortSignal.timeout(this.timeoutMs)
|
|
18814
19948
|
});
|
|
18815
19949
|
return res.ok ? { ok: true, status: res.status } : { ok: false, status: res.status };
|
|
18816
|
-
} catch (
|
|
18817
|
-
return { ok: false, error:
|
|
19950
|
+
} catch (err8) {
|
|
19951
|
+
return { ok: false, error: err8 instanceof Error ? err8.message : String(err8) };
|
|
18818
19952
|
}
|
|
18819
19953
|
}
|
|
18820
19954
|
/**
|
|
@@ -18877,7 +20011,7 @@ function feishuText(event) {
|
|
|
18877
20011
|
// src/bootstrap.ts
|
|
18878
20012
|
var activeImageRuntimeBootstrapSession;
|
|
18879
20013
|
function createImageRuntimeBootstrapSession(initialGeneration) {
|
|
18880
|
-
const openAIOperationRegistry = new
|
|
20014
|
+
const openAIOperationRegistry = new import_core7.OpenAIOperationRegistry();
|
|
18881
20015
|
const imageRuntimeManager = new ImageRuntimeManager(initialGeneration);
|
|
18882
20016
|
const unregisterContributions = [];
|
|
18883
20017
|
try {
|
|
@@ -18956,12 +20090,12 @@ function buildDaemon(config, paths) {
|
|
|
18956
20090
|
setSecretBox(secretBox3);
|
|
18957
20091
|
setSecretBox2(secretBox3);
|
|
18958
20092
|
const decryptedConfig = decryptConfigSecrets(config, secretBox3);
|
|
18959
|
-
const accountAllowanceStore = new
|
|
20093
|
+
const accountAllowanceStore = new import_AccountAllowanceStore10.AccountAllowanceStore(
|
|
18960
20094
|
Date.now,
|
|
18961
20095
|
void 0,
|
|
18962
20096
|
new JsonAccountAllowancePersistence(defaultAccountAllowancePath(paths.configPath))
|
|
18963
20097
|
);
|
|
18964
|
-
(0,
|
|
20098
|
+
(0, import_AccountAllowanceStore10.setSharedAccountAllowanceStore)(accountAllowanceStore);
|
|
18965
20099
|
(0, import_AccountAllowanceScheduling5.getSharedAccountAllowanceScheduling)().configure(
|
|
18966
20100
|
(0, import_outbound_api10.normalizeServerConfig)(decryptedConfig.server).allowanceScheduling
|
|
18967
20101
|
);
|
|
@@ -18986,20 +20120,20 @@ function buildDaemon(config, paths) {
|
|
|
18986
20120
|
claudeAllowanceRefreshScheduler.configure(
|
|
18987
20121
|
(0, import_outbound_api10.normalizeServerConfig)(decryptedConfig.server).allowanceScheduling
|
|
18988
20122
|
);
|
|
18989
|
-
const subscriptionAccounts = new
|
|
18990
|
-
(0,
|
|
18991
|
-
const subscriptionRegistry = new
|
|
20123
|
+
const subscriptionAccounts = new import_subscriptions12.SubscriptionAccountService(credentialStore);
|
|
20124
|
+
(0, import_subscriptions12.setSubscriptionAccountService)(subscriptionAccounts);
|
|
20125
|
+
const subscriptionRegistry = new import_subscriptions12.SubscriptionProviderRegistry(
|
|
18992
20126
|
subscriptionAccounts,
|
|
18993
20127
|
credentialStore
|
|
18994
20128
|
);
|
|
18995
|
-
(0,
|
|
20129
|
+
(0, import_subscriptions12.setSubscriptionProviderRegistry)(subscriptionRegistry);
|
|
18996
20130
|
setServerProxyConfig(decryptedConfig.server?.proxy);
|
|
18997
|
-
(0,
|
|
20131
|
+
(0, import_upstreamFetch16.setUpstreamProxyResolver)(
|
|
18998
20132
|
createUpstreamProxyResolver({
|
|
18999
20133
|
getAccountProxy: (providerId, accountId) => credentialStore.getAccountProxy(providerId, accountId)
|
|
19000
20134
|
})
|
|
19001
20135
|
);
|
|
19002
|
-
(0, import_gemini_code_assist_resolver.setGeminiCodeAssistResolver)((0,
|
|
20136
|
+
(0, import_gemini_code_assist_resolver.setGeminiCodeAssistResolver)((0, import_GeminiCodeAssistProjectResolver2.getGeminiCodeAssistProjectResolver)());
|
|
19003
20137
|
const autoDisableStore = new AutoDisableStore();
|
|
19004
20138
|
const providerKeyQuotaService = new ProviderKeyQuotaService(secretBox3);
|
|
19005
20139
|
const apiKeyPool = new import_ApiKeyPoolService.ApiKeyPoolService(
|
|
@@ -19018,7 +20152,7 @@ function buildDaemon(config, paths) {
|
|
|
19018
20152
|
const pricingEngine = new import_usage2.PricingEngine(pricingStore, logger, {
|
|
19019
20153
|
// Catalog egress follows the same global/env proxy policy as every other
|
|
19020
20154
|
// daemon upstream call; no provider/account override applies here.
|
|
19021
|
-
fetchImpl: ((input, init) => (0,
|
|
20155
|
+
fetchImpl: ((input, init) => (0, import_upstreamFetch16.fetchUpstream)(String(input), init ?? {}))
|
|
19022
20156
|
});
|
|
19023
20157
|
const pricingRefreshScheduler = new PricingRefreshScheduler(
|
|
19024
20158
|
pricingEngine,
|
|
@@ -19303,7 +20437,7 @@ function buildDaemon(config, paths) {
|
|
|
19303
20437
|
// — `server.proxy.byProvider[...]` was silently skipped — and the call was
|
|
19304
20438
|
// excluded from the upstream trace, so a failing login left no evidence.
|
|
19305
20439
|
// `redactBodies` keeps the code/verifier + minted token out of that trace.
|
|
19306
|
-
oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => (0,
|
|
20440
|
+
oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => (0, import_upstreamFetch16.fetchUpstream)(url, init, { providerId, redactBodies: true }),
|
|
19307
20441
|
subscriptionAccountAppender: credentialStore,
|
|
19308
20442
|
// Codex interactive OAuth (app-parity-2 child 5) — the async loopback flow store
|
|
19309
20443
|
// + the one-shot 127.0.0.1:1455 listener. Token captured + persisted daemon-side;
|
|
@@ -19315,6 +20449,9 @@ function buildDaemon(config, paths) {
|
|
|
19315
20449
|
// paste; the app shows the verification URL + user code and polls the
|
|
19316
20450
|
// token-free status). Token captured + persisted daemon-side.
|
|
19317
20451
|
kimiSessions: new CodexOAuthSessionStore(),
|
|
20452
|
+
// Grok interactive OAuth — the same async DEVICE-CODE shape as kimi.
|
|
20453
|
+
grokSessions: new CodexOAuthSessionStore(),
|
|
20454
|
+
copilotSessions: new CodexOAuthSessionStore(),
|
|
19318
20455
|
// Migration pack (app-parity child 6, design D2/D3) — the concrete credential
|
|
19319
20456
|
// store provides BOTH the full DECRYPTED read (`getFullConfig`, export) and
|
|
19320
20457
|
// the multi-account append (`appendProviderAccount`, import re-encrypts at-
|
|
@@ -19373,7 +20510,7 @@ function buildDaemon(config, paths) {
|
|
|
19373
20510
|
});
|
|
19374
20511
|
const webhookDispatcher = new WebhookDispatcher({
|
|
19375
20512
|
logger,
|
|
19376
|
-
fetchImpl: (url, init) => (0,
|
|
20513
|
+
fetchImpl: (url, init) => (0, import_upstreamFetch16.fetchUpstream)(url, init)
|
|
19377
20514
|
});
|
|
19378
20515
|
setWebhookRuntime(webhookDispatcher, (0, import_SubscriptionAccountHealth4.getSharedAccountHealth)());
|
|
19379
20516
|
const auditWriter = new AuditWriter(auditDir, logger);
|
|
@@ -19453,9 +20590,9 @@ function resetDaemonSingletonsForTests() {
|
|
|
19453
20590
|
(0, import_provider_proxy4.__resetProviderProxyForTests)();
|
|
19454
20591
|
(0, import_outbound_api10.__resetOutboundApiServerForTests)();
|
|
19455
20592
|
(0, import_subscriptionRegistryPort.setSubscriptionRegistryForOutbound)(null);
|
|
19456
|
-
(0,
|
|
19457
|
-
(0,
|
|
19458
|
-
(0,
|
|
20593
|
+
(0, import_subscriptions12.setSubscriptionProviderRegistry)(null);
|
|
20594
|
+
(0, import_subscriptions12.setSubscriptionAccountService)(null);
|
|
20595
|
+
(0, import_upstreamFetch16.setUpstreamProxyResolver)(null);
|
|
19459
20596
|
setServerProxyConfig(void 0);
|
|
19460
20597
|
(0, import_gemini_code_assist_resolver.setGeminiCodeAssistResolver)(null);
|
|
19461
20598
|
setSecretBox(null);
|
|
@@ -19464,7 +20601,7 @@ function resetDaemonSingletonsForTests() {
|
|
|
19464
20601
|
resetAuditRuntimeForTests();
|
|
19465
20602
|
resetBillingRuntimeForTests();
|
|
19466
20603
|
(0, import_SubscriptionIdentityStore3.__resetSharedIdentityStoreForTests)();
|
|
19467
|
-
(0,
|
|
20604
|
+
(0, import_AccountAllowanceStore10.__resetSharedAccountAllowanceStoreForTests)();
|
|
19468
20605
|
(0, import_AccountAllowanceScheduling5.__resetSharedAccountAllowanceSchedulingForTests)();
|
|
19469
20606
|
(0, import_usage2.__resetSharedUsageThroughputTrackerForTests)();
|
|
19470
20607
|
}
|