@omnicross/daemon 0.1.6 → 0.1.8
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 +1186 -200
- package/dist/cli.js +1200 -191
- package/dist/index.cjs +1118 -147
- package/dist/index.d.cts +101 -26
- package/dist/index.d.ts +101 -26
- package/dist/index.js +1135 -139
- package/package.json +63 -63
package/dist/index.cjs
CHANGED
|
@@ -53,20 +53,21 @@ __export(src_exports, {
|
|
|
53
53
|
module.exports = __toCommonJS(src_exports);
|
|
54
54
|
|
|
55
55
|
// src/bootstrap.ts
|
|
56
|
-
var
|
|
56
|
+
var import_node_fs23 = require("fs");
|
|
57
57
|
var import_audit_types = require("@omnicross/contracts/audit-types");
|
|
58
58
|
var import_billing_types = require("@omnicross/contracts/billing-types");
|
|
59
59
|
var import_GeminiCodeAssistProjectResolver = require("@omnicross/core/auth/GeminiCodeAssistProjectResolver");
|
|
60
60
|
var import_ApiKeyPoolService = require("@omnicross/core/completion/ApiKeyPoolService");
|
|
61
61
|
var import_outbound_api4 = require("@omnicross/core/outbound-api");
|
|
62
62
|
var import_subscriptionRegistryPort = require("@omnicross/core/outbound-api/subscriptionRegistryPort");
|
|
63
|
-
var
|
|
63
|
+
var import_SubscriptionAccountHealth4 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
|
|
64
64
|
var import_AccountAllowanceStore4 = require("@omnicross/core/pipeline/AccountAllowanceStore");
|
|
65
|
-
var
|
|
65
|
+
var import_AccountAllowanceScheduling5 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
|
|
66
66
|
var import_upstreamFetch8 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
67
67
|
var import_SubscriptionIdentityStore3 = require("@omnicross/core/provider-proxy/identity/SubscriptionIdentityStore");
|
|
68
68
|
var import_gemini_code_assist_resolver = require("@omnicross/core/ports/gemini-code-assist-resolver");
|
|
69
|
-
var
|
|
69
|
+
var import_provider_proxy4 = require("@omnicross/core/provider-proxy");
|
|
70
|
+
var import_cli_launcher2 = require("@omnicross/cli-launcher");
|
|
70
71
|
var import_outbound_api5 = require("@omnicross/core/outbound-api");
|
|
71
72
|
var import_usage = require("@omnicross/core/usage");
|
|
72
73
|
var import_subscriptions4 = require("@omnicross/subscriptions");
|
|
@@ -147,7 +148,7 @@ async function runCodexLoopback(sessionId, codeVerifier, state, signal, deps) {
|
|
|
147
148
|
const code = await deps.codexAwaitLoopback(state, void 0, signal);
|
|
148
149
|
const result = await import_subscriptions.codexOAuth.exchangeCodeForTokens(
|
|
149
150
|
{ authorizationCode: code, codeVerifier, state },
|
|
150
|
-
deps.oauthExchangeFetch
|
|
151
|
+
deps.oauthExchangeFetch("codex")
|
|
151
152
|
);
|
|
152
153
|
const expiresAt = new Date(Date.now() + result.expiresIn * 1e3).toISOString();
|
|
153
154
|
const block = {
|
|
@@ -649,6 +650,17 @@ function handleAuditQuery(req, res, reader) {
|
|
|
649
650
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
650
651
|
res.end(JSON.stringify({ records }));
|
|
651
652
|
}
|
|
653
|
+
async function handleAuditStatsQuery(req, res, reader) {
|
|
654
|
+
const url = new URL(req.url ?? "/", "http://localhost");
|
|
655
|
+
const query2 = {};
|
|
656
|
+
const from = intParam(url.searchParams.get("from"));
|
|
657
|
+
if (from !== void 0) query2.from = from;
|
|
658
|
+
const to = intParam(url.searchParams.get("to"));
|
|
659
|
+
if (to !== void 0) query2.to = to;
|
|
660
|
+
const stats = reader ? await reader(query2) : { requestCount: 0, errorCount: 0, complete: true };
|
|
661
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
662
|
+
res.end(JSON.stringify(stats));
|
|
663
|
+
}
|
|
652
664
|
|
|
653
665
|
// src/admin/billingStatusApi.ts
|
|
654
666
|
function handleBillingStatus(res, reader) {
|
|
@@ -745,6 +757,88 @@ async function handleWebhookTest(req, res) {
|
|
|
745
757
|
res.end(JSON.stringify({ result }));
|
|
746
758
|
}
|
|
747
759
|
|
|
760
|
+
// src/admin/routeLeaseApi.ts
|
|
761
|
+
var import_provider_proxy = require("@omnicross/core/provider-proxy");
|
|
762
|
+
var MAX_BODY_BYTES = 64 * 1024;
|
|
763
|
+
var SAFE_LEASE_ID = /^[A-Za-z0-9-]{1,128}$/u;
|
|
764
|
+
async function readJson(req) {
|
|
765
|
+
const chunks = [];
|
|
766
|
+
let bytes = 0;
|
|
767
|
+
for await (const chunk of req) {
|
|
768
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
769
|
+
bytes += buffer.length;
|
|
770
|
+
if (bytes > MAX_BODY_BYTES) throw new import_provider_proxy.RouteLeaseError("invalid_request", "request body is too large");
|
|
771
|
+
chunks.push(buffer);
|
|
772
|
+
}
|
|
773
|
+
if (chunks.length === 0) return {};
|
|
774
|
+
try {
|
|
775
|
+
return JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
776
|
+
} catch {
|
|
777
|
+
throw new import_provider_proxy.RouteLeaseError("invalid_request", "request body is not valid JSON");
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
function json(res, status, body, noStore = false) {
|
|
781
|
+
res.statusCode = status;
|
|
782
|
+
res.setHeader("Content-Type", "application/json");
|
|
783
|
+
if (noStore) res.setHeader("Cache-Control", "no-store");
|
|
784
|
+
res.end(JSON.stringify(body));
|
|
785
|
+
}
|
|
786
|
+
function leaseId(value) {
|
|
787
|
+
if (!value || !SAFE_LEASE_ID.test(value)) throw new import_provider_proxy.RouteLeaseError("invalid_request", "lease id is invalid");
|
|
788
|
+
return value;
|
|
789
|
+
}
|
|
790
|
+
function header(req, name) {
|
|
791
|
+
const value = req.headers[name.toLowerCase()];
|
|
792
|
+
return Array.isArray(value) ? value[0] : value;
|
|
793
|
+
}
|
|
794
|
+
function writeError(res, error, noStore) {
|
|
795
|
+
const safe = error instanceof import_provider_proxy.RouteLeaseError ? error : new import_provider_proxy.RouteLeaseError("upstream_unavailable", "route lease operation failed safely");
|
|
796
|
+
if (safe.retryAfterSeconds !== void 0) res.setHeader("Retry-After", String(safe.retryAfterSeconds));
|
|
797
|
+
json(res, safe.status, safe.toResponse(), noStore);
|
|
798
|
+
}
|
|
799
|
+
async function handleRouteLeaseApi(req, res, path2, deps) {
|
|
800
|
+
const method = (req.method ?? "GET").toUpperCase();
|
|
801
|
+
const noStore = method === "POST" && (path2 === "/admin/api/route-leases" || path2.endsWith("/renew"));
|
|
802
|
+
try {
|
|
803
|
+
if (!(0, import_provider_proxy.isLoopbackAddress)(req.socket.remoteAddress)) {
|
|
804
|
+
throw new import_provider_proxy.RouteLeaseError("control_unauthorized", "route lease control plane is loopback only");
|
|
805
|
+
}
|
|
806
|
+
const manager = deps.routeLeaseManager;
|
|
807
|
+
if (!manager) throw new import_provider_proxy.RouteLeaseError("daemon_not_ready", "route lease manager is unavailable");
|
|
808
|
+
const base = "/admin/api/route-leases";
|
|
809
|
+
const suffix = path2.slice(base.length).replace(/^\/+|\/+$/gu, "");
|
|
810
|
+
const segments = suffix ? suffix.split("/") : [];
|
|
811
|
+
if (segments.length === 1 && segments[0] === "capabilities") {
|
|
812
|
+
if (method !== "GET" && method !== "HEAD") throw new import_provider_proxy.RouteLeaseError("invalid_request", "method is not allowed");
|
|
813
|
+
return json(res, 200, import_provider_proxy.ROUTE_LEASE_CAPABILITIES);
|
|
814
|
+
}
|
|
815
|
+
if (segments.length === 0) {
|
|
816
|
+
if (method === "GET") return json(res, 200, { leases: manager.list() });
|
|
817
|
+
if (method === "POST") {
|
|
818
|
+
const outcome = await manager.createFromRequest(await readJson(req), header(req, "idempotency-key"));
|
|
819
|
+
return json(res, outcome.created ? 201 : 200, outcome.result, true);
|
|
820
|
+
}
|
|
821
|
+
throw new import_provider_proxy.RouteLeaseError("invalid_request", "method is not allowed");
|
|
822
|
+
}
|
|
823
|
+
const id = leaseId(segments[0]);
|
|
824
|
+
if (segments.length === 1) {
|
|
825
|
+
if (method === "GET") return json(res, 200, manager.get(id));
|
|
826
|
+
if (method === "DELETE") return json(res, 200, manager.release(id));
|
|
827
|
+
throw new import_provider_proxy.RouteLeaseError("invalid_request", "method is not allowed");
|
|
828
|
+
}
|
|
829
|
+
if (segments.length === 2 && segments[1] === "renew" && method === "POST") {
|
|
830
|
+
const body = await readJson(req);
|
|
831
|
+
const ttl = (0, import_provider_proxy.normalizeRouteLeaseTtl)(
|
|
832
|
+
body && typeof body === "object" && !Array.isArray(body) ? body.ttlSeconds : void 0
|
|
833
|
+
);
|
|
834
|
+
return json(res, 200, manager.renew(id, ttl), true);
|
|
835
|
+
}
|
|
836
|
+
throw new import_provider_proxy.RouteLeaseError("lease_not_found", "route lease endpoint was not found");
|
|
837
|
+
} catch (error) {
|
|
838
|
+
writeError(res, error, noStore);
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
|
|
748
842
|
// src/admin/adminApi.ts
|
|
749
843
|
var import_node_http = __toESM(require("http"), 1);
|
|
750
844
|
var import_outbound_api2 = require("@omnicross/core/outbound-api");
|
|
@@ -2144,7 +2238,13 @@ function listMappablePresets() {
|
|
|
2144
2238
|
name: preset.name,
|
|
2145
2239
|
apiFormat: resolved.format,
|
|
2146
2240
|
baseUrl: preset.api_base_url,
|
|
2147
|
-
models: Array.isArray(preset.models) ? preset.models : []
|
|
2241
|
+
models: Array.isArray(preset.models) ? preset.models : [],
|
|
2242
|
+
nameKey: preset.nameKey,
|
|
2243
|
+
icon: preset.icon,
|
|
2244
|
+
description: preset.description,
|
|
2245
|
+
features: preset.features,
|
|
2246
|
+
website: preset.website,
|
|
2247
|
+
modelsEndpoint: preset.modelsEndpoint
|
|
2148
2248
|
});
|
|
2149
2249
|
}
|
|
2150
2250
|
return { mappable, excluded };
|
|
@@ -2533,7 +2633,7 @@ async function handleOAuthComplete(providerId, body, deps) {
|
|
|
2533
2633
|
const rawCode = typeof body["code"] === "string" ? body["code"] : "";
|
|
2534
2634
|
if (!sessionId) return err2(400, "oauth complete requires { sessionId }");
|
|
2535
2635
|
if (!rawCode) return err2(400, "oauth complete requires { code }");
|
|
2536
|
-
const session = deps.oauthSessions.
|
|
2636
|
+
const session = deps.oauthSessions.peek(sessionId);
|
|
2537
2637
|
if (!session) return err2(410, "oauth session is unknown, expired, or already used");
|
|
2538
2638
|
if (session.providerId !== providerId) {
|
|
2539
2639
|
return err2(400, `oauth session does not match provider '${providerId}'`);
|
|
@@ -2547,13 +2647,15 @@ async function handleOAuthComplete(providerId, body, deps) {
|
|
|
2547
2647
|
}
|
|
2548
2648
|
code = splitCode;
|
|
2549
2649
|
}
|
|
2650
|
+
const exchangeFetch = deps.oauthExchangeFetch(providerId);
|
|
2550
2651
|
let block;
|
|
2551
2652
|
try {
|
|
2552
|
-
block = providerId === "claude" ? await exchangeClaude(code, session.codeVerifier, session.state,
|
|
2653
|
+
block = providerId === "claude" ? await exchangeClaude(code, session.codeVerifier, session.state, exchangeFetch) : await exchangeGemini(code, session.codeVerifier, exchangeFetch);
|
|
2553
2654
|
} catch (exchangeError) {
|
|
2554
2655
|
const reason = exchangeError instanceof Error ? exchangeError.message : "token exchange failed";
|
|
2555
2656
|
return err2(502, `oauth token exchange failed for '${providerId}': ${reason}`);
|
|
2556
2657
|
}
|
|
2658
|
+
deps.oauthSessions.consume(sessionId);
|
|
2557
2659
|
const label = typeof body["label"] === "string" && body["label"].trim() ? body["label"].trim() : void 0;
|
|
2558
2660
|
await deps.subscriptionAccountAppender.appendProviderAccount(providerId, block, label);
|
|
2559
2661
|
const status = await statusEntryFor(deps.subscriptionAccounts, providerId);
|
|
@@ -2592,8 +2694,34 @@ async function exchangeGemini(code, codeVerifier, exchangeFetch) {
|
|
|
2592
2694
|
var import_node_child_process = require("child_process");
|
|
2593
2695
|
var import_node_crypto6 = require("crypto");
|
|
2594
2696
|
var import_node_fs6 = require("fs");
|
|
2697
|
+
var import_node_net = require("net");
|
|
2698
|
+
var import_node_os3 = require("os");
|
|
2595
2699
|
var import_node_path5 = require("path");
|
|
2596
2700
|
var import_cli_launcher = require("@omnicross/cli-launcher");
|
|
2701
|
+
var import_provider_proxy2 = require("@omnicross/core/provider-proxy");
|
|
2702
|
+
|
|
2703
|
+
// src/routeLeaseRenewal.ts
|
|
2704
|
+
var TERMINAL_LEASE_TTL_SECONDS = 600;
|
|
2705
|
+
var TERMINAL_LEASE_RENEW_INTERVAL_MS = 5 * 60 * 1e3;
|
|
2706
|
+
var TERMINAL_LEASE_MAX_LIFETIME_MS = 24 * 60 * 60 * 1e3;
|
|
2707
|
+
function startTerminalLeaseRenewal(manager, leaseId2) {
|
|
2708
|
+
const stopAt = Date.now() + TERMINAL_LEASE_MAX_LIFETIME_MS;
|
|
2709
|
+
const timer = setInterval(() => {
|
|
2710
|
+
if (Date.now() >= stopAt) {
|
|
2711
|
+
clearInterval(timer);
|
|
2712
|
+
return;
|
|
2713
|
+
}
|
|
2714
|
+
try {
|
|
2715
|
+
manager.renew(leaseId2, TERMINAL_LEASE_TTL_SECONDS);
|
|
2716
|
+
} catch {
|
|
2717
|
+
clearInterval(timer);
|
|
2718
|
+
}
|
|
2719
|
+
}, TERMINAL_LEASE_RENEW_INTERVAL_MS);
|
|
2720
|
+
timer.unref?.();
|
|
2721
|
+
return () => clearInterval(timer);
|
|
2722
|
+
}
|
|
2723
|
+
|
|
2724
|
+
// src/admin/cliLaunch.ts
|
|
2597
2725
|
var LAUNCHABLE_CLIS = [
|
|
2598
2726
|
{ id: "claude", displayName: "Claude Code", command: "claude" },
|
|
2599
2727
|
{ id: "codex", displayName: "Codex CLI", command: "codex" },
|
|
@@ -2674,34 +2802,183 @@ async function buildLaunchEnv(cli, llmConfig, target) {
|
|
|
2674
2802
|
function shq(s) {
|
|
2675
2803
|
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
2676
2804
|
}
|
|
2677
|
-
var
|
|
2805
|
+
var MAC_TERMINAL_BOOTSTRAP_SOURCE = `
|
|
2806
|
+
'use strict';
|
|
2807
|
+
const fs = require('node:fs');
|
|
2808
|
+
const net = require('node:net');
|
|
2809
|
+
const { spawn } = require('node:child_process');
|
|
2810
|
+
const [socketPath, launchDir, cwd, command, ...args] = process.argv.slice(2);
|
|
2811
|
+
let payload = '';
|
|
2812
|
+
const socket = net.createConnection(socketPath);
|
|
2813
|
+
socket.setEncoding('utf8');
|
|
2814
|
+
socket.on('data', (chunk) => { payload += chunk; });
|
|
2815
|
+
socket.on('end', () => {
|
|
2816
|
+
const descriptor = JSON.parse(payload);
|
|
2817
|
+
if (!descriptor || Array.isArray(descriptor) || Object.values(descriptor).some((value) => typeof value !== 'string')) {
|
|
2818
|
+
throw new Error('invalid terminal launch descriptor');
|
|
2819
|
+
}
|
|
2820
|
+
try { fs.rmSync(launchDir, { recursive: true, force: true }); } catch {}
|
|
2821
|
+
const child = spawn(command, args, {
|
|
2822
|
+
cwd: cwd || undefined,
|
|
2823
|
+
env: { ...process.env, ...descriptor },
|
|
2824
|
+
stdio: 'inherit',
|
|
2825
|
+
});
|
|
2826
|
+
child.on('error', (error) => { console.error(error.message); process.exitCode = 1; });
|
|
2827
|
+
child.on('exit', (code, signal) => {
|
|
2828
|
+
if (signal) process.kill(process.pid, signal);
|
|
2829
|
+
else process.exitCode = code == null ? 1 : code;
|
|
2830
|
+
});
|
|
2831
|
+
});
|
|
2832
|
+
socket.on('error', (error) => { console.error(error.message); process.exitCode = 1; });
|
|
2833
|
+
`;
|
|
2834
|
+
var MAC_TERMINAL_IPC_TIMEOUT_MS = 12e4;
|
|
2835
|
+
function openTerminal({ cli, command, extraArgs, env, cwd, platform, onFailure }, spawnProcess = import_node_child_process.spawn, macIpc = {}) {
|
|
2678
2836
|
const childEnv = { ...process.env, ...env };
|
|
2679
2837
|
if (platform === "win32") {
|
|
2680
2838
|
const args = ["/c", "start", `"omnicross ${cli}"`];
|
|
2681
2839
|
if (cwd) args.push("/D", `"${cwd}"`);
|
|
2682
2840
|
args.push("cmd", "/k", command, ...extraArgs);
|
|
2683
|
-
(
|
|
2841
|
+
spawnProcess(process.env["ComSpec"] || "cmd.exe", args, {
|
|
2684
2842
|
env: childEnv,
|
|
2685
2843
|
windowsVerbatimArguments: true,
|
|
2686
2844
|
detached: true,
|
|
2687
2845
|
stdio: "ignore"
|
|
2688
2846
|
}).unref();
|
|
2689
|
-
return
|
|
2847
|
+
return () => {
|
|
2848
|
+
};
|
|
2690
2849
|
}
|
|
2691
|
-
const exportLine = Object.entries(env).map(([k, v]) => `export ${k}=${shq(v)}`).join("; ");
|
|
2692
2850
|
const runLine = [command, ...extraArgs].map(shq).join(" ");
|
|
2693
|
-
const script = `${
|
|
2851
|
+
const script = `${cwd ? `cd ${shq(cwd)}; ` : ""}${runLine}`;
|
|
2694
2852
|
if (platform === "darwin") {
|
|
2695
|
-
const
|
|
2696
|
-
(0,
|
|
2697
|
-
|
|
2853
|
+
const launchDir = (0, import_node_fs6.mkdtempSync)((0, import_node_path5.join)((0, import_node_os3.tmpdir)(), "omnicross-terminal-"));
|
|
2854
|
+
const commandFile = (0, import_node_path5.join)(launchDir, "launch.command");
|
|
2855
|
+
const bootstrapFile = (0, import_node_path5.join)(launchDir, "bootstrap.cjs");
|
|
2856
|
+
const socketPath = macIpc.socketPath ?? (0, import_node_path5.join)(launchDir, "descriptor.sock");
|
|
2857
|
+
const openerEnv = { ...process.env };
|
|
2858
|
+
for (const key of Object.keys(env)) delete openerEnv[key];
|
|
2859
|
+
let claimed = false;
|
|
2860
|
+
let cleaned = false;
|
|
2861
|
+
let failureNotified = false;
|
|
2862
|
+
let timer;
|
|
2863
|
+
const notifyFailure = () => {
|
|
2864
|
+
cleanup();
|
|
2865
|
+
if (failureNotified) return;
|
|
2866
|
+
failureNotified = true;
|
|
2867
|
+
try {
|
|
2868
|
+
onFailure?.();
|
|
2869
|
+
} catch {
|
|
2870
|
+
}
|
|
2871
|
+
};
|
|
2872
|
+
const handleLaunchFailure = () => {
|
|
2873
|
+
if (claimed) cleanup();
|
|
2874
|
+
else notifyFailure();
|
|
2875
|
+
};
|
|
2876
|
+
const sockets = /* @__PURE__ */ new Set();
|
|
2877
|
+
const server = (0, import_node_net.createServer)((socket) => {
|
|
2878
|
+
socket.unref();
|
|
2879
|
+
sockets.add(socket);
|
|
2880
|
+
socket.once("close", () => sockets.delete(socket));
|
|
2881
|
+
try {
|
|
2882
|
+
macIpc.onAccepted?.(socket);
|
|
2883
|
+
} catch {
|
|
2884
|
+
cleanup();
|
|
2885
|
+
return;
|
|
2886
|
+
}
|
|
2887
|
+
if (claimed || cleaned) {
|
|
2888
|
+
socket.destroy();
|
|
2889
|
+
return;
|
|
2890
|
+
}
|
|
2891
|
+
claimed = true;
|
|
2892
|
+
try {
|
|
2893
|
+
macIpc.onClaimed?.();
|
|
2894
|
+
if (cleaned) return;
|
|
2895
|
+
socket.end(JSON.stringify(env), cleanup);
|
|
2896
|
+
} catch {
|
|
2897
|
+
cleanup();
|
|
2898
|
+
}
|
|
2899
|
+
});
|
|
2900
|
+
const cleanup = () => {
|
|
2901
|
+
if (!cleaned) {
|
|
2902
|
+
cleaned = true;
|
|
2903
|
+
if (timer) clearTimeout(timer);
|
|
2904
|
+
for (const socket of sockets) socket.destroy();
|
|
2905
|
+
sockets.clear();
|
|
2906
|
+
try {
|
|
2907
|
+
server.close();
|
|
2908
|
+
} catch {
|
|
2909
|
+
}
|
|
2910
|
+
}
|
|
2911
|
+
try {
|
|
2912
|
+
if (macIpc.removeArtifacts) {
|
|
2913
|
+
macIpc.removeArtifacts(launchDir);
|
|
2914
|
+
} else {
|
|
2915
|
+
(0, import_node_fs6.rmSync)(launchDir, {
|
|
2916
|
+
recursive: true,
|
|
2917
|
+
force: true,
|
|
2918
|
+
maxRetries: 3,
|
|
2919
|
+
retryDelay: 20
|
|
2920
|
+
});
|
|
2921
|
+
}
|
|
2922
|
+
} catch {
|
|
2923
|
+
}
|
|
2924
|
+
};
|
|
2925
|
+
try {
|
|
2926
|
+
(0, import_node_fs6.writeFileSync)(bootstrapFile, MAC_TERMINAL_BOOTSTRAP_SOURCE, { encoding: "utf8", mode: 448 });
|
|
2927
|
+
(0, import_node_fs6.writeFileSync)(commandFile, `#!/bin/bash
|
|
2928
|
+
rm -f -- "$0"
|
|
2929
|
+
exec ${shq(process.execPath)} ${shq(bootstrapFile)} ${shq(socketPath)} ${shq(launchDir)} ${shq(cwd ?? "")} ${runLine}
|
|
2930
|
+
`, {
|
|
2931
|
+
encoding: "utf8",
|
|
2932
|
+
mode: 448
|
|
2933
|
+
});
|
|
2934
|
+
(0, import_node_fs6.chmodSync)(commandFile, 448);
|
|
2935
|
+
(0, import_node_fs6.chmodSync)(bootstrapFile, 448);
|
|
2936
|
+
server.once("error", handleLaunchFailure);
|
|
2937
|
+
server.listen(socketPath, () => {
|
|
2938
|
+
if (cleaned) return;
|
|
2939
|
+
try {
|
|
2940
|
+
macIpc.onListening?.();
|
|
2941
|
+
if (cleaned) return;
|
|
2942
|
+
if (process.platform !== "win32") (0, import_node_fs6.chmodSync)(socketPath, 384);
|
|
2943
|
+
const opener = spawnProcess("open", ["-n", "-a", "Terminal", commandFile], {
|
|
2944
|
+
env: openerEnv,
|
|
2945
|
+
detached: true,
|
|
2946
|
+
stdio: "ignore"
|
|
2947
|
+
});
|
|
2948
|
+
opener.once("error", handleLaunchFailure);
|
|
2949
|
+
opener.unref();
|
|
2950
|
+
server.unref();
|
|
2951
|
+
} catch {
|
|
2952
|
+
handleLaunchFailure();
|
|
2953
|
+
}
|
|
2954
|
+
});
|
|
2955
|
+
timer = setTimeout(handleLaunchFailure, macIpc.timeoutMs ?? MAC_TERMINAL_IPC_TIMEOUT_MS);
|
|
2956
|
+
timer.unref?.();
|
|
2957
|
+
return cleanup;
|
|
2958
|
+
} catch (error) {
|
|
2959
|
+
cleanup();
|
|
2960
|
+
throw error;
|
|
2961
|
+
}
|
|
2698
2962
|
}
|
|
2699
|
-
(
|
|
2963
|
+
spawnProcess("x-terminal-emulator", ["-e", "bash", "-lc", `${script}; exec bash`], {
|
|
2964
|
+
env: childEnv,
|
|
2700
2965
|
detached: true,
|
|
2701
2966
|
stdio: "ignore"
|
|
2702
2967
|
}).unref();
|
|
2703
|
-
|
|
2968
|
+
return () => {
|
|
2969
|
+
};
|
|
2970
|
+
}
|
|
2971
|
+
var defaultTerminalOpener = (input) => openTerminal(input);
|
|
2704
2972
|
var sessions = /* @__PURE__ */ new Map();
|
|
2973
|
+
function resetCliSessions() {
|
|
2974
|
+
for (const s of sessions.values()) {
|
|
2975
|
+
try {
|
|
2976
|
+
s.onSessionEnd();
|
|
2977
|
+
} catch {
|
|
2978
|
+
}
|
|
2979
|
+
}
|
|
2980
|
+
sessions.clear();
|
|
2981
|
+
}
|
|
2705
2982
|
function errBody(message) {
|
|
2706
2983
|
return { error: { type: "admin_api_error", message } };
|
|
2707
2984
|
}
|
|
@@ -2756,29 +3033,81 @@ async function handleCliLaunch(cli, body, ctx) {
|
|
|
2756
3033
|
} catch (err5) {
|
|
2757
3034
|
return { status: 400, body: errBody(err5 instanceof Error ? err5.message : "no launch target") };
|
|
2758
3035
|
}
|
|
3036
|
+
const id = (0, import_node_crypto6.randomUUID)();
|
|
3037
|
+
let leaseId2;
|
|
2759
3038
|
let launch;
|
|
2760
3039
|
try {
|
|
2761
|
-
|
|
3040
|
+
if ((cli === "claude" || cli === "codex") && ctx.routeLeaseManager) {
|
|
3041
|
+
const outcome = await ctx.routeLeaseManager.createFromRequest({
|
|
3042
|
+
schemaVersion: import_provider_proxy2.ROUTE_LEASE_REQUEST_SCHEMA,
|
|
3043
|
+
consumer: "omnicross-terminal",
|
|
3044
|
+
runtime: cli,
|
|
3045
|
+
upstream: { kind: "provider", providerId: target.providerId },
|
|
3046
|
+
model: target.model,
|
|
3047
|
+
execution: { sessionId: id }
|
|
3048
|
+
}, `omnicross-terminal:${id}`);
|
|
3049
|
+
leaseId2 = outcome.result.leaseId;
|
|
3050
|
+
const stopRenewal = startTerminalLeaseRenewal(ctx.routeLeaseManager, leaseId2);
|
|
3051
|
+
launch = {
|
|
3052
|
+
env: outcome.result.launch.env,
|
|
3053
|
+
extraArgs: outcome.result.launch.extraArgs,
|
|
3054
|
+
onSessionEnd: () => {
|
|
3055
|
+
stopRenewal();
|
|
3056
|
+
ctx.routeLeaseManager?.release(outcome.result.leaseId);
|
|
3057
|
+
}
|
|
3058
|
+
};
|
|
3059
|
+
} else {
|
|
3060
|
+
launch = await buildLaunchEnv(cli, ctx.llmConfig, target);
|
|
3061
|
+
}
|
|
2762
3062
|
} catch (err5) {
|
|
2763
|
-
|
|
3063
|
+
const status = err5 instanceof import_provider_proxy2.RouteLeaseError ? err5.status : 400;
|
|
3064
|
+
return { status, body: errBody(err5 instanceof Error ? err5.message : "failed to build launch env") };
|
|
2764
3065
|
}
|
|
2765
3066
|
const cwd = typeof body["cwd"] === "string" && body["cwd"].trim() ? body["cwd"].trim() : void 0;
|
|
2766
3067
|
const opener = ctx.opener ?? defaultTerminalOpener;
|
|
3068
|
+
let openerCleanup;
|
|
3069
|
+
let ended = false;
|
|
3070
|
+
let published = false;
|
|
3071
|
+
const onSessionEnd = () => {
|
|
3072
|
+
if (ended) return;
|
|
3073
|
+
ended = true;
|
|
3074
|
+
if (published) sessions.delete(id);
|
|
3075
|
+
try {
|
|
3076
|
+
openerCleanup?.();
|
|
3077
|
+
} finally {
|
|
3078
|
+
launch.onSessionEnd();
|
|
3079
|
+
}
|
|
3080
|
+
};
|
|
2767
3081
|
try {
|
|
2768
|
-
opener({
|
|
3082
|
+
const cleanup = opener({
|
|
3083
|
+
cli,
|
|
3084
|
+
command: meta.command,
|
|
3085
|
+
extraArgs: launch.extraArgs ?? [],
|
|
3086
|
+
env: launch.env,
|
|
3087
|
+
cwd,
|
|
3088
|
+
platform,
|
|
3089
|
+
onFailure: onSessionEnd
|
|
3090
|
+
});
|
|
3091
|
+
if (cleanup) openerCleanup = cleanup;
|
|
2769
3092
|
} catch (err5) {
|
|
2770
|
-
|
|
3093
|
+
onSessionEnd();
|
|
2771
3094
|
return { status: 500, body: errBody(err5 instanceof Error ? err5.message : "failed to open terminal") };
|
|
2772
3095
|
}
|
|
2773
|
-
|
|
3096
|
+
if (ended) {
|
|
3097
|
+
openerCleanup?.();
|
|
3098
|
+
return { status: 500, body: errBody("failed to open terminal") };
|
|
3099
|
+
}
|
|
2774
3100
|
sessions.set(id, {
|
|
2775
3101
|
id,
|
|
2776
3102
|
cli,
|
|
2777
3103
|
providerId: target.providerId,
|
|
2778
3104
|
model: target.model,
|
|
3105
|
+
...leaseId2 ? { leaseId: leaseId2 } : {},
|
|
2779
3106
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2780
|
-
onSessionEnd
|
|
3107
|
+
onSessionEnd
|
|
2781
3108
|
});
|
|
3109
|
+
published = true;
|
|
3110
|
+
if (ended) sessions.delete(id);
|
|
2782
3111
|
return { status: 200, body: { sessionId: id, providerId: target.providerId, model: target.model } };
|
|
2783
3112
|
}
|
|
2784
3113
|
|
|
@@ -2798,8 +3127,8 @@ function validateAuditSegment(patch) {
|
|
|
2798
3127
|
}
|
|
2799
3128
|
}
|
|
2800
3129
|
const maxBodyBytes = audit["maxBodyBytes"];
|
|
2801
|
-
if (maxBodyBytes !== void 0 && (typeof maxBodyBytes !== "number" || !Number.isFinite(maxBodyBytes) || maxBodyBytes <
|
|
2802
|
-
errors.push("audit.maxBodyBytes must be a non-negative number");
|
|
3130
|
+
if (maxBodyBytes !== void 0 && (typeof maxBodyBytes !== "number" || !Number.isFinite(maxBodyBytes) || maxBodyBytes < -1)) {
|
|
3131
|
+
errors.push("audit.maxBodyBytes must be -1 or a non-negative number");
|
|
2803
3132
|
}
|
|
2804
3133
|
const retentionDays = audit["retentionDays"];
|
|
2805
3134
|
if (retentionDays !== void 0 && (typeof retentionDays !== "number" || !Number.isFinite(retentionDays) || retentionDays < 0)) {
|
|
@@ -3234,18 +3563,16 @@ function preserveWebhookSecrets(incoming, current) {
|
|
|
3234
3563
|
}
|
|
3235
3564
|
|
|
3236
3565
|
// src/audit/auditRuntime.ts
|
|
3237
|
-
var import_node_path6 = require("path");
|
|
3238
3566
|
var import_auditSink = require("@omnicross/core/pipeline/auditSink");
|
|
3239
3567
|
var import_upstreamTrace = require("@omnicross/core/pipeline/upstreamTrace");
|
|
3240
3568
|
var writer = null;
|
|
3241
3569
|
var sweeper = null;
|
|
3242
|
-
|
|
3243
|
-
function setAuditRuntime(w, s, dir) {
|
|
3570
|
+
function setAuditRuntime(w, s) {
|
|
3244
3571
|
writer = w;
|
|
3245
3572
|
sweeper = s;
|
|
3246
|
-
auditDir = dir;
|
|
3247
3573
|
}
|
|
3248
3574
|
function applyAuditConfig(config) {
|
|
3575
|
+
(0, import_upstreamTrace.setUpstreamTracePath)(null);
|
|
3249
3576
|
const enabled = config?.enabled === true && writer !== null;
|
|
3250
3577
|
if (enabled && config) {
|
|
3251
3578
|
(0, import_auditSink.setAuditCaptureConfig)(config);
|
|
@@ -3255,11 +3582,9 @@ function applyAuditConfig(config) {
|
|
|
3255
3582
|
sweeper.configure(config);
|
|
3256
3583
|
sweeper.start();
|
|
3257
3584
|
}
|
|
3258
|
-
(0, import_upstreamTrace.setUpstreamTracePath)(config.captureBodies ? (0, import_node_path6.join)(auditDir, "upstream-trace.jsonl") : null);
|
|
3259
3585
|
} else {
|
|
3260
3586
|
(0, import_auditSink.setAuditCaptureConfig)(null);
|
|
3261
3587
|
(0, import_auditSink.setAuditSink)(null);
|
|
3262
|
-
(0, import_upstreamTrace.setUpstreamTracePath)(null);
|
|
3263
3588
|
if (sweeper) {
|
|
3264
3589
|
if (config) sweeper.configure(config);
|
|
3265
3590
|
sweeper.dispose();
|
|
@@ -3273,7 +3598,6 @@ function resetAuditRuntimeForTests() {
|
|
|
3273
3598
|
if (sweeper) sweeper.dispose();
|
|
3274
3599
|
writer = null;
|
|
3275
3600
|
sweeper = null;
|
|
3276
|
-
auditDir = "";
|
|
3277
3601
|
}
|
|
3278
3602
|
|
|
3279
3603
|
// src/billing/billingRuntime.ts
|
|
@@ -3675,7 +3999,7 @@ function sealPack(bundleJson, passphrase) {
|
|
|
3675
3999
|
cipher.setAAD(aadFor(PACK_MAGIC, PACK_VERSION, KDF_ALGORITHM));
|
|
3676
4000
|
const ciphertext = Buffer.concat([cipher.update(bundleJson, "utf8"), cipher.final()]);
|
|
3677
4001
|
const tag = cipher.getAuthTag();
|
|
3678
|
-
const
|
|
4002
|
+
const header2 = {
|
|
3679
4003
|
magic: PACK_MAGIC,
|
|
3680
4004
|
v: PACK_VERSION,
|
|
3681
4005
|
kdf: KDF_ALGORITHM,
|
|
@@ -3686,7 +4010,7 @@ function sealPack(bundleJson, passphrase) {
|
|
|
3686
4010
|
iv: iv.toString("base64"),
|
|
3687
4011
|
tag: tag.toString("base64")
|
|
3688
4012
|
};
|
|
3689
|
-
return `${PACK_PREFIX}${toB64Url(JSON.stringify(
|
|
4013
|
+
return `${PACK_PREFIX}${toB64Url(JSON.stringify(header2))}.${ciphertext.toString("base64")}`;
|
|
3690
4014
|
}
|
|
3691
4015
|
function parsePack(packString) {
|
|
3692
4016
|
if (typeof packString !== "string" || !packString.startsWith(PACK_PREFIX)) {
|
|
@@ -3697,28 +4021,28 @@ function parsePack(packString) {
|
|
|
3697
4021
|
if (dot < 0) throw new PackAuthError("migration pack is malformed (missing body)");
|
|
3698
4022
|
const headerB64Url = rest.slice(0, dot);
|
|
3699
4023
|
const ctB64 = rest.slice(dot + 1);
|
|
3700
|
-
let
|
|
4024
|
+
let header2;
|
|
3701
4025
|
try {
|
|
3702
|
-
|
|
4026
|
+
header2 = JSON.parse(fromB64Url(headerB64Url));
|
|
3703
4027
|
} catch {
|
|
3704
4028
|
throw new PackAuthError("migration pack is malformed (unreadable header)");
|
|
3705
4029
|
}
|
|
3706
|
-
if (!
|
|
4030
|
+
if (!header2 || header2.magic !== PACK_MAGIC || header2.v !== PACK_VERSION || header2.kdf !== KDF_ALGORITHM || typeof header2.salt !== "string" || typeof header2.iv !== "string" || typeof header2.tag !== "string" || typeof header2.N !== "number" || typeof header2.r !== "number" || typeof header2.p !== "number") {
|
|
3707
4031
|
throw new PackAuthError("migration pack is malformed (unsupported header)");
|
|
3708
4032
|
}
|
|
3709
4033
|
const ciphertext = Buffer.from(ctB64, "base64");
|
|
3710
|
-
return { header, ciphertext };
|
|
4034
|
+
return { header: header2, ciphertext };
|
|
3711
4035
|
}
|
|
3712
4036
|
function openPack(packString, passphrase) {
|
|
3713
4037
|
assertPassphraseStrength(passphrase);
|
|
3714
|
-
const { header, ciphertext } = parsePack(packString);
|
|
3715
|
-
const salt = Buffer.from(
|
|
3716
|
-
const iv = Buffer.from(
|
|
3717
|
-
const tag = Buffer.from(
|
|
4038
|
+
const { header: header2, ciphertext } = parsePack(packString);
|
|
4039
|
+
const salt = Buffer.from(header2.salt, "base64");
|
|
4040
|
+
const iv = Buffer.from(header2.iv, "base64");
|
|
4041
|
+
const tag = Buffer.from(header2.tag, "base64");
|
|
3718
4042
|
if (iv.length !== IV_BYTES2 || tag.length !== TAG_BYTES2) {
|
|
3719
4043
|
throw new PackAuthError("migration pack is malformed (invalid iv/tag length)");
|
|
3720
4044
|
}
|
|
3721
|
-
const key = deriveKey(passphrase, salt,
|
|
4045
|
+
const key = deriveKey(passphrase, salt, header2.N, header2.r, header2.p);
|
|
3722
4046
|
const decipher = (0, import_node_crypto8.createDecipheriv)("aes-256-gcm", key, iv);
|
|
3723
4047
|
decipher.setAAD(aadFor(PACK_MAGIC, PACK_VERSION, KDF_ALGORITHM));
|
|
3724
4048
|
decipher.setAuthTag(tag);
|
|
@@ -4054,10 +4378,10 @@ function writeJson2(res, status, body) {
|
|
|
4054
4378
|
res.writeHead(status, { "Content-Type": "application/json" });
|
|
4055
4379
|
res.end(JSON.stringify(body));
|
|
4056
4380
|
}
|
|
4057
|
-
function
|
|
4381
|
+
function writeError2(res, status, message) {
|
|
4058
4382
|
writeJson2(res, status, { error: { type: "account_allowance_error", message } });
|
|
4059
4383
|
}
|
|
4060
|
-
function
|
|
4384
|
+
function readJson2(req) {
|
|
4061
4385
|
return new Promise((resolve2, reject) => {
|
|
4062
4386
|
const chunks = [];
|
|
4063
4387
|
req.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
|
|
@@ -4083,10 +4407,10 @@ function allowanceProvider(value) {
|
|
|
4083
4407
|
return value === "claude" || value === "codex" ? value : null;
|
|
4084
4408
|
}
|
|
4085
4409
|
async function handleAccountAllowanceApi(req, res, method, rest, service) {
|
|
4086
|
-
if (!service) return
|
|
4410
|
+
if (!service) return writeError2(res, 501, "account allowance service is not available");
|
|
4087
4411
|
if (method === "GET" && rest.length === 1 && rest[0] === "scheduling") {
|
|
4088
4412
|
if (!service.getSchedulingStatus) {
|
|
4089
|
-
return
|
|
4413
|
+
return writeError2(res, 501, "allowance scheduling diagnostics are not available");
|
|
4090
4414
|
}
|
|
4091
4415
|
return writeJson2(res, 200, { scheduling: service.getSchedulingStatus() });
|
|
4092
4416
|
}
|
|
@@ -4094,30 +4418,32 @@ async function handleAccountAllowanceApi(req, res, method, rest, service) {
|
|
|
4094
4418
|
const params = query(req);
|
|
4095
4419
|
const pathProvider = rest.length >= 2 ? rest[0] : null;
|
|
4096
4420
|
const providerId = allowanceProvider(pathProvider ?? params.get("providerId") ?? params.get("provider"));
|
|
4097
|
-
if (providerId === null) return
|
|
4421
|
+
if (providerId === null) return writeError2(res, 400, "providerId must be claude or codex");
|
|
4098
4422
|
const accountId = rest.length >= 2 ? rest[1] : params.get("accountId") ?? void 0;
|
|
4099
4423
|
const allowances = await service.list({ providerId, accountId });
|
|
4100
4424
|
return writeJson2(res, 200, { allowances });
|
|
4101
4425
|
}
|
|
4102
4426
|
if (method === "POST" && rest[0] === "refresh") {
|
|
4103
|
-
const body = await
|
|
4427
|
+
const body = await readJson2(req);
|
|
4104
4428
|
const requestedProvider = allowanceProvider(
|
|
4105
4429
|
typeof body["providerId"] === "string" ? body["providerId"] : "claude"
|
|
4106
4430
|
);
|
|
4107
4431
|
if (requestedProvider !== "claude") {
|
|
4108
|
-
return
|
|
4432
|
+
return writeError2(res, 400, "only Claude allowances support explicit refresh");
|
|
4109
4433
|
}
|
|
4110
4434
|
const accountId = typeof body["accountId"] === "string" && body["accountId"].trim() ? body["accountId"].trim() : void 0;
|
|
4111
4435
|
const allowances = await service.refreshClaude(accountId);
|
|
4112
4436
|
if (accountId && allowances.length === 0) {
|
|
4113
|
-
return
|
|
4437
|
+
return writeError2(res, 404, `Claude account '${accountId}' not found`);
|
|
4114
4438
|
}
|
|
4115
4439
|
return writeJson2(res, 200, { allowances });
|
|
4116
4440
|
}
|
|
4117
|
-
return
|
|
4441
|
+
return writeError2(res, 405, `method ${method} not allowed on account allowances`);
|
|
4118
4442
|
}
|
|
4119
4443
|
|
|
4120
4444
|
// src/admin/adminApi.ts
|
|
4445
|
+
var import_AccountRouteActivity = require("@omnicross/core/pipeline/AccountRouteActivity");
|
|
4446
|
+
var import_ServerOverloadCounter = require("@omnicross/core/pipeline/ServerOverloadCounter");
|
|
4121
4447
|
function readBody(req) {
|
|
4122
4448
|
return new Promise((resolve2, reject) => {
|
|
4123
4449
|
const chunks = [];
|
|
@@ -4154,6 +4480,9 @@ function toKeyInfo(row) {
|
|
|
4154
4480
|
id: row.id,
|
|
4155
4481
|
name: row.name,
|
|
4156
4482
|
keyPrefix: row.keyPrefix,
|
|
4483
|
+
// True only when a reversible `keySecret` envelope was persisted at creation
|
|
4484
|
+
// — gates the UI "view key" eye. Legacy hash-only rows read as absent.
|
|
4485
|
+
revealable: Boolean(row.keySecret),
|
|
4157
4486
|
enabled: row.enabled,
|
|
4158
4487
|
createdAt: row.createdAt,
|
|
4159
4488
|
lastUsedAt: row.lastUsedAt,
|
|
@@ -4809,7 +5138,13 @@ function handlePresets(res, method) {
|
|
|
4809
5138
|
name: p.name,
|
|
4810
5139
|
apiFormat: p.apiFormat,
|
|
4811
5140
|
baseUrl: p.baseUrl,
|
|
4812
|
-
models: p.models
|
|
5141
|
+
models: p.models,
|
|
5142
|
+
nameKey: p.nameKey,
|
|
5143
|
+
icon: p.icon,
|
|
5144
|
+
description: p.description,
|
|
5145
|
+
features: p.features,
|
|
5146
|
+
website: p.website,
|
|
5147
|
+
modelsEndpoint: p.modelsEndpoint
|
|
4813
5148
|
}));
|
|
4814
5149
|
return writeJson3(res, 200, { presets, excluded });
|
|
4815
5150
|
}
|
|
@@ -4843,12 +5178,27 @@ async function handleKeys(req, res, method, rest, deps) {
|
|
|
4843
5178
|
plaintextOnce: created.plaintextOnce
|
|
4844
5179
|
});
|
|
4845
5180
|
}
|
|
5181
|
+
if (method === "GET" && rest.length === 2 && rest[1] === "reveal") {
|
|
5182
|
+
const revealed = await deps.keyDb.outboundApiKeysReveal(rest[0]);
|
|
5183
|
+
if (revealed !== null) return writeJson3(res, 200, { key: revealed });
|
|
5184
|
+
const exists = (await deps.keyDb.outboundApiKeysList()).some((r) => r.id === rest[0]);
|
|
5185
|
+
if (!exists) return writeJsonError(res, 404, `key '${rest[0]}' not found`);
|
|
5186
|
+
return writeJsonError(
|
|
5187
|
+
res,
|
|
5188
|
+
409,
|
|
5189
|
+
`key '${rest[0]}' is not revealable (created before revealable key storage)`
|
|
5190
|
+
);
|
|
5191
|
+
}
|
|
4846
5192
|
const id = rest[0];
|
|
4847
5193
|
const action = rest[1];
|
|
4848
5194
|
if (method === "POST" && id && action === "revoke") {
|
|
4849
5195
|
const ok = await deps.keyDb.outboundApiKeysRevoke(id);
|
|
4850
5196
|
return writeJson3(res, ok ? 200 : 404, { ok });
|
|
4851
5197
|
}
|
|
5198
|
+
if (method === "DELETE" && id && !action) {
|
|
5199
|
+
const ok = await deps.keyDb.outboundApiKeysDelete(id);
|
|
5200
|
+
return writeJson3(res, ok ? 200 : 404, { ok });
|
|
5201
|
+
}
|
|
4852
5202
|
if (method === "POST" && id && action === "enabled") {
|
|
4853
5203
|
const body = await readJsonBody3(req);
|
|
4854
5204
|
const enabled = body["enabled"] === true;
|
|
@@ -5025,6 +5375,40 @@ async function handleServer(req, res, method, deps) {
|
|
|
5025
5375
|
return writeJsonError(res, 405, `method ${method} not allowed on server`);
|
|
5026
5376
|
}
|
|
5027
5377
|
async function handleAccounts(req, res, method, rest, deps) {
|
|
5378
|
+
if (rest[0] === "route-activity" && rest.length === 1) {
|
|
5379
|
+
if (method !== "GET") {
|
|
5380
|
+
return writeJsonError(res, 405, `method ${method} not allowed on account route activity`);
|
|
5381
|
+
}
|
|
5382
|
+
const query2 = requestQuery(req);
|
|
5383
|
+
const parsedLimit = Number(query2.get("limit") ?? "100");
|
|
5384
|
+
const records = (0, import_AccountRouteActivity.getSharedAccountRouteActivity)().list({
|
|
5385
|
+
providerId: query2.get("providerId") ?? void 0,
|
|
5386
|
+
accountId: query2.get("accountId") ?? void 0,
|
|
5387
|
+
sessionKey: query2.get("sessionKey") ?? void 0,
|
|
5388
|
+
limit: Number.isFinite(parsedLimit) ? parsedLimit : 100
|
|
5389
|
+
});
|
|
5390
|
+
return writeJson3(res, 200, {
|
|
5391
|
+
available: true,
|
|
5392
|
+
records,
|
|
5393
|
+
capacity: import_AccountRouteActivity.ACCOUNT_ROUTE_ACTIVITY_LIMIT,
|
|
5394
|
+
collectedAt: Date.now()
|
|
5395
|
+
});
|
|
5396
|
+
}
|
|
5397
|
+
if (rest[0] === "overload-counters" && rest.length === 1) {
|
|
5398
|
+
if (method !== "GET") {
|
|
5399
|
+
return writeJsonError(res, 405, `method ${method} not allowed on overload counters`);
|
|
5400
|
+
}
|
|
5401
|
+
const query2 = requestQuery(req);
|
|
5402
|
+
const entries = (0, import_ServerOverloadCounter.getSharedOverloadCounter)().list({
|
|
5403
|
+
providerId: query2.get("providerId") ?? void 0,
|
|
5404
|
+
accountId: query2.get("accountId") ?? void 0
|
|
5405
|
+
});
|
|
5406
|
+
return writeJson3(res, 200, {
|
|
5407
|
+
available: true,
|
|
5408
|
+
entries,
|
|
5409
|
+
collectedAt: Date.now()
|
|
5410
|
+
});
|
|
5411
|
+
}
|
|
5028
5412
|
if (rest[0] === "allowances") {
|
|
5029
5413
|
return handleAccountAllowanceApi(
|
|
5030
5414
|
req,
|
|
@@ -5171,8 +5555,13 @@ async function handleAccounts(req, res, method, rest, deps) {
|
|
|
5171
5555
|
if (!(listed[providerId] ?? []).some((account) => account.id === accountId)) {
|
|
5172
5556
|
return writeJsonError(res, 404, `account '${accountId}' not found`);
|
|
5173
5557
|
}
|
|
5174
|
-
const result = await deps.accountProbeService.
|
|
5175
|
-
return writeJson3(res, 200, {
|
|
5558
|
+
const result = await deps.accountProbeService.testAccountConnection(providerId, accountId);
|
|
5559
|
+
return writeJson3(res, 200, {
|
|
5560
|
+
ok: result.ok,
|
|
5561
|
+
marked: result.marked,
|
|
5562
|
+
tier: result.tier,
|
|
5563
|
+
model: result.model
|
|
5564
|
+
});
|
|
5176
5565
|
}
|
|
5177
5566
|
if (method === "POST" && rest[2] === "label") {
|
|
5178
5567
|
const accountId = rest[1];
|
|
@@ -5281,6 +5670,7 @@ async function handleCli(req, res, method, rest, deps) {
|
|
|
5281
5670
|
const result = await handleCliLaunch(cli, body, {
|
|
5282
5671
|
llmConfig: deps.llmConfig,
|
|
5283
5672
|
providers,
|
|
5673
|
+
routeLeaseManager: deps.routeLeaseManager,
|
|
5284
5674
|
opener: deps.cliTerminalOpener,
|
|
5285
5675
|
probe: deps.cliPathProbe
|
|
5286
5676
|
});
|
|
@@ -5451,7 +5841,7 @@ function proxyToOutbound(res, outboundPort, path2, key, body) {
|
|
|
5451
5841
|
var import_node_fs7 = require("fs");
|
|
5452
5842
|
var import_promises = require("fs/promises");
|
|
5453
5843
|
var import_node_module = require("module");
|
|
5454
|
-
var
|
|
5844
|
+
var import_node_path6 = __toESM(require("path"), 1);
|
|
5455
5845
|
var import_meta = {};
|
|
5456
5846
|
var CONTENT_TYPES = {
|
|
5457
5847
|
".html": "text/html; charset=utf-8",
|
|
@@ -5472,13 +5862,13 @@ var CONTENT_TYPES = {
|
|
|
5472
5862
|
function resolveUiDist() {
|
|
5473
5863
|
const fromEnv = process.env["OMNICROSS_UI_DIST"];
|
|
5474
5864
|
if (fromEnv) {
|
|
5475
|
-
return (0, import_node_fs7.existsSync)(
|
|
5865
|
+
return (0, import_node_fs7.existsSync)(import_node_path6.default.join(fromEnv, "index.html")) ? import_node_path6.default.resolve(fromEnv) : null;
|
|
5476
5866
|
}
|
|
5477
5867
|
try {
|
|
5478
5868
|
const req = (0, import_node_module.createRequire)(typeof __filename !== "undefined" ? __filename : import_meta.url);
|
|
5479
5869
|
const pkgJson = req.resolve("@omnicross/ui/package.json");
|
|
5480
|
-
const dist =
|
|
5481
|
-
return (0, import_node_fs7.existsSync)(
|
|
5870
|
+
const dist = import_node_path6.default.join(import_node_path6.default.dirname(pkgJson), "dist");
|
|
5871
|
+
return (0, import_node_fs7.existsSync)(import_node_path6.default.join(dist, "index.html")) ? dist : null;
|
|
5482
5872
|
} catch {
|
|
5483
5873
|
return null;
|
|
5484
5874
|
}
|
|
@@ -5520,16 +5910,16 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
|
|
|
5520
5910
|
res.end(JSON.stringify({ error: { type: "bad_request", message: "invalid path" } }));
|
|
5521
5911
|
return true;
|
|
5522
5912
|
}
|
|
5523
|
-
const filePath =
|
|
5524
|
-
if (filePath !== uiDist && !filePath.startsWith(uiDist +
|
|
5913
|
+
const filePath = import_node_path6.default.resolve(uiDist, rel === "" ? "index.html" : rel);
|
|
5914
|
+
if (filePath !== uiDist && !filePath.startsWith(uiDist + import_node_path6.default.sep)) {
|
|
5525
5915
|
res.writeHead(403, { "Content-Type": "application/json" });
|
|
5526
5916
|
res.end(JSON.stringify({ error: { type: "forbidden", message: "path outside ui root" } }));
|
|
5527
5917
|
return true;
|
|
5528
5918
|
}
|
|
5529
5919
|
let target = filePath;
|
|
5530
5920
|
if (!(0, import_node_fs7.existsSync)(target) || (0, import_node_fs7.statSync)(target).isDirectory()) {
|
|
5531
|
-
if (
|
|
5532
|
-
target =
|
|
5921
|
+
if (import_node_path6.default.extname(rel) === "") {
|
|
5922
|
+
target = import_node_path6.default.join(uiDist, "index.html");
|
|
5533
5923
|
} else {
|
|
5534
5924
|
res.writeHead(404, { "Content-Type": "application/json" });
|
|
5535
5925
|
res.end(JSON.stringify({ error: { type: "not_found", message: "no such ui asset" } }));
|
|
@@ -5537,14 +5927,14 @@ async function handleUiStatic(req, res, urlPath, uiDist) {
|
|
|
5537
5927
|
}
|
|
5538
5928
|
}
|
|
5539
5929
|
const body = await (0, import_promises.readFile)(target);
|
|
5540
|
-
const type = CONTENT_TYPES[
|
|
5930
|
+
const type = CONTENT_TYPES[import_node_path6.default.extname(target).toLowerCase()] ?? "application/octet-stream";
|
|
5541
5931
|
res.writeHead(200, { "Content-Type": type, "Content-Length": body.length });
|
|
5542
5932
|
res.end(req.method === "HEAD" ? void 0 : body);
|
|
5543
5933
|
return true;
|
|
5544
5934
|
}
|
|
5545
5935
|
|
|
5546
5936
|
// src/admin/version.ts
|
|
5547
|
-
var DAEMON_VERSION = true ? "0.1.
|
|
5937
|
+
var DAEMON_VERSION = true ? "0.1.8" : "0.0.0-dev";
|
|
5548
5938
|
|
|
5549
5939
|
// src/admin/AdminServer.ts
|
|
5550
5940
|
var LOOPBACK_ADDR = "127.0.0.1";
|
|
@@ -5652,6 +6042,10 @@ var AdminServer = class {
|
|
|
5652
6042
|
handleAuditQuery(req, res, this.deps.auditReader);
|
|
5653
6043
|
return;
|
|
5654
6044
|
}
|
|
6045
|
+
if (path2 === "/admin/api/audit/stats" && (req.method === "GET" || req.method === "HEAD")) {
|
|
6046
|
+
await handleAuditStatsQuery(req, res, this.deps.auditStatsReader);
|
|
6047
|
+
return;
|
|
6048
|
+
}
|
|
5655
6049
|
if (path2 === "/admin/api/billing-status" && (req.method === "GET" || req.method === "HEAD")) {
|
|
5656
6050
|
handleBillingStatus(res, this.deps.billingStatusReader);
|
|
5657
6051
|
return;
|
|
@@ -5660,6 +6054,10 @@ var AdminServer = class {
|
|
|
5660
6054
|
await handleWebhookTest(req, res);
|
|
5661
6055
|
return;
|
|
5662
6056
|
}
|
|
6057
|
+
if (path2 === "/admin/api/route-leases" || path2.startsWith("/admin/api/route-leases/")) {
|
|
6058
|
+
await handleRouteLeaseApi(req, res, path2, this.deps);
|
|
6059
|
+
return;
|
|
6060
|
+
}
|
|
5663
6061
|
if (path2.startsWith("/admin/api/")) {
|
|
5664
6062
|
await handleAdminApi(req, res, path2, this.deps);
|
|
5665
6063
|
return;
|
|
@@ -5671,8 +6069,8 @@ var AdminServer = class {
|
|
|
5671
6069
|
}
|
|
5672
6070
|
/** Constant-time bearer/header check against the configured token. */
|
|
5673
6071
|
isAuthorized(req, token) {
|
|
5674
|
-
const
|
|
5675
|
-
const bearer = typeof
|
|
6072
|
+
const header2 = req.headers["authorization"];
|
|
6073
|
+
const bearer = typeof header2 === "string" && header2.startsWith("Bearer ") ? header2.slice("Bearer ".length).trim() : void 0;
|
|
5676
6074
|
const xToken = req.headers["x-admin-token"];
|
|
5677
6075
|
const presented = bearer ?? (typeof xToken === "string" ? xToken.trim() : void 0);
|
|
5678
6076
|
return constantTimeEquals(presented, token);
|
|
@@ -5768,20 +6166,36 @@ var OAuthSessionStore = class {
|
|
|
5768
6166
|
return sessionId;
|
|
5769
6167
|
}
|
|
5770
6168
|
/**
|
|
5771
|
-
*
|
|
5772
|
-
*
|
|
5773
|
-
* dropped). A `null` return means the completer must reject (no
|
|
5774
|
-
* write).
|
|
6169
|
+
* NON-DESTRUCTIVE lookup: return the session for `sessionId`, or `null` when
|
|
6170
|
+
* it is unknown, already consumed, or past its TTL (an expired entry is
|
|
6171
|
+
* dropped here). A `null` return means the completer must reject (no
|
|
6172
|
+
* exchange, no write).
|
|
6173
|
+
*
|
|
6174
|
+
* Deliberately NOT a consume: the completer peeks, runs the token exchange,
|
|
6175
|
+
* and only {@link consume}s once a token has actually been minted. Consuming
|
|
6176
|
+
* up-front burned the session on EVERY failed exchange (a mistyped/expired
|
|
6177
|
+
* pasted code, a proxy hiccup), so the user's natural retry hit
|
|
6178
|
+
* "session is unknown, expired, or already used" and the login became
|
|
6179
|
+
* unrecoverable without restarting the whole flow.
|
|
5775
6180
|
*/
|
|
5776
|
-
|
|
6181
|
+
peek(sessionId) {
|
|
5777
6182
|
this.sweep();
|
|
5778
6183
|
const session = this.sessions.get(sessionId);
|
|
5779
6184
|
if (!session) return null;
|
|
5780
|
-
|
|
5781
|
-
|
|
6185
|
+
if (Date.now() - session.createdAt > this.ttlMs) {
|
|
6186
|
+
this.sessions.delete(sessionId);
|
|
6187
|
+
return null;
|
|
6188
|
+
}
|
|
5782
6189
|
return session;
|
|
5783
6190
|
}
|
|
5784
|
-
/**
|
|
6191
|
+
/**
|
|
6192
|
+
* SINGLE-USE burn: drop the session so the same `sessionId` can never be
|
|
6193
|
+
* completed twice. Called ONLY after a successful token exchange.
|
|
6194
|
+
*/
|
|
6195
|
+
consume(sessionId) {
|
|
6196
|
+
this.sessions.delete(sessionId);
|
|
6197
|
+
}
|
|
6198
|
+
/** Drop every session past its TTL. Called on each put/peek. */
|
|
5785
6199
|
sweep() {
|
|
5786
6200
|
const now = Date.now();
|
|
5787
6201
|
for (const [id, session] of this.sessions) {
|
|
@@ -5796,6 +6210,10 @@ var LOOPBACK_HOST = "127.0.0.1";
|
|
|
5796
6210
|
var LOOPBACK_PORT = 1455;
|
|
5797
6211
|
var CALLBACK_PATH = "/auth/callback";
|
|
5798
6212
|
var DEFAULT_TIMEOUT_MS = 5 * 6e4;
|
|
6213
|
+
var HTML_HEADERS = {
|
|
6214
|
+
"Content-Type": "text/html",
|
|
6215
|
+
Connection: "close"
|
|
6216
|
+
};
|
|
5799
6217
|
function pageHtml(message) {
|
|
5800
6218
|
return `<!doctype html><meta charset="utf-8"><title>omnicross login</title><body style="font-family:sans-serif;padding:2rem"><h2>${message}</h2><p>You can close this window and return to the terminal.</p></body>`;
|
|
5801
6219
|
}
|
|
@@ -5806,30 +6224,31 @@ function awaitLoopbackCode(expectedState, timeoutMs = DEFAULT_TIMEOUT_MS, signal
|
|
|
5806
6224
|
if (settled) return;
|
|
5807
6225
|
settled = true;
|
|
5808
6226
|
clearTimeout(timer);
|
|
5809
|
-
|
|
6227
|
+
fn();
|
|
6228
|
+
server2.close();
|
|
5810
6229
|
};
|
|
5811
6230
|
const server = (0, import_node_http3.createServer)((req, res) => {
|
|
5812
6231
|
const url = new URL(req.url ?? "", `http://${LOOPBACK_HOST}:${LOOPBACK_PORT}`);
|
|
5813
6232
|
if (url.pathname !== CALLBACK_PATH) {
|
|
5814
|
-
res.writeHead(404,
|
|
6233
|
+
res.writeHead(404, HTML_HEADERS);
|
|
5815
6234
|
res.end(pageHtml("Not found"));
|
|
5816
6235
|
return;
|
|
5817
6236
|
}
|
|
5818
6237
|
const code = url.searchParams.get("code");
|
|
5819
6238
|
const state = url.searchParams.get("state");
|
|
5820
6239
|
if (!code) {
|
|
5821
|
-
res.writeHead(400,
|
|
6240
|
+
res.writeHead(400, HTML_HEADERS);
|
|
5822
6241
|
res.end(pageHtml("Login failed: missing authorization code."));
|
|
5823
6242
|
finish(server, () => reject(new Error("login: callback did not include an authorization code")));
|
|
5824
6243
|
return;
|
|
5825
6244
|
}
|
|
5826
6245
|
if (state !== expectedState) {
|
|
5827
|
-
res.writeHead(400,
|
|
6246
|
+
res.writeHead(400, HTML_HEADERS);
|
|
5828
6247
|
res.end(pageHtml("Login failed: state mismatch."));
|
|
5829
6248
|
finish(server, () => reject(new Error("login: callback state did not match (possible CSRF) \u2014 aborting")));
|
|
5830
6249
|
return;
|
|
5831
6250
|
}
|
|
5832
|
-
res.writeHead(200,
|
|
6251
|
+
res.writeHead(200, HTML_HEADERS);
|
|
5833
6252
|
res.end(pageHtml("Login complete."));
|
|
5834
6253
|
finish(server, () => resolve2(code));
|
|
5835
6254
|
});
|
|
@@ -5926,30 +6345,30 @@ function createPoolKeysLoader(getProviderRow, autoDisabled) {
|
|
|
5926
6345
|
}
|
|
5927
6346
|
|
|
5928
6347
|
// src/commands/paths.ts
|
|
5929
|
-
var
|
|
6348
|
+
var import_node_path7 = require("path");
|
|
5930
6349
|
function defaultVouchersPath(configPath) {
|
|
5931
|
-
return (0,
|
|
6350
|
+
return (0, import_node_path7.join)((0, import_node_path7.dirname)(configPath), "vouchers.json");
|
|
5932
6351
|
}
|
|
5933
6352
|
function defaultIntegrationsPath(configPath) {
|
|
5934
|
-
return (0,
|
|
6353
|
+
return (0, import_node_path7.join)((0, import_node_path7.dirname)(configPath), "integrations.json");
|
|
5935
6354
|
}
|
|
5936
6355
|
function defaultPricingPath(configPath) {
|
|
5937
|
-
return (0,
|
|
6356
|
+
return (0, import_node_path7.join)((0, import_node_path7.dirname)(configPath), "pricing.json");
|
|
5938
6357
|
}
|
|
5939
6358
|
function defaultPricingRefreshStatePath(configPath) {
|
|
5940
|
-
return (0,
|
|
6359
|
+
return (0, import_node_path7.join)((0, import_node_path7.dirname)(configPath), "pricing-refresh.json");
|
|
5941
6360
|
}
|
|
5942
6361
|
function defaultAccountAllowancePath(configPath) {
|
|
5943
|
-
return (0,
|
|
6362
|
+
return (0, import_node_path7.join)((0, import_node_path7.dirname)(configPath), "allowance-cache.json");
|
|
5944
6363
|
}
|
|
5945
6364
|
function defaultUsageEventsPath(configPath) {
|
|
5946
|
-
return (0,
|
|
6365
|
+
return (0, import_node_path7.join)((0, import_node_path7.dirname)(configPath), "usage-events.jsonl");
|
|
5947
6366
|
}
|
|
5948
6367
|
function defaultAuditDir(configPath) {
|
|
5949
|
-
return (0,
|
|
6368
|
+
return (0, import_node_path7.join)((0, import_node_path7.dirname)(configPath), "audit");
|
|
5950
6369
|
}
|
|
5951
6370
|
function defaultBillingDir(configPath) {
|
|
5952
|
-
return (0,
|
|
6371
|
+
return (0, import_node_path7.join)((0, import_node_path7.dirname)(configPath), "billing");
|
|
5953
6372
|
}
|
|
5954
6373
|
|
|
5955
6374
|
// src/ports/ConfigFileProviderConfigSource.ts
|
|
@@ -6342,8 +6761,12 @@ var JsonlUsageEventStore = class {
|
|
|
6342
6761
|
reasoningTokens: 0,
|
|
6343
6762
|
costUsd: 0,
|
|
6344
6763
|
costSavedByCacheUsd: 0,
|
|
6345
|
-
eventCount: 0
|
|
6764
|
+
eventCount: 0,
|
|
6765
|
+
cacheEligibleEventCount: 0,
|
|
6766
|
+
coldCacheEventCount: 0,
|
|
6767
|
+
medianCacheHitRate: null
|
|
6346
6768
|
};
|
|
6769
|
+
const perEventHitRates = [];
|
|
6347
6770
|
for (const row of this.readRows(range)) {
|
|
6348
6771
|
totals.inputTokens += row.inputTokens;
|
|
6349
6772
|
totals.outputTokens += row.outputTokens;
|
|
@@ -6353,7 +6776,14 @@ var JsonlUsageEventStore = class {
|
|
|
6353
6776
|
totals.costUsd += row.costUsd;
|
|
6354
6777
|
totals.costSavedByCacheUsd += row.costSavedByCacheUsd;
|
|
6355
6778
|
totals.eventCount += 1;
|
|
6779
|
+
const promptSideTokens = row.inputTokens + row.cacheReadTokens + row.cacheCreationTokens;
|
|
6780
|
+
if (promptSideTokens > 0) {
|
|
6781
|
+
totals.cacheEligibleEventCount += 1;
|
|
6782
|
+
if (row.cacheReadTokens === 0) totals.coldCacheEventCount += 1;
|
|
6783
|
+
perEventHitRates.push(row.cacheReadTokens / promptSideTokens);
|
|
6784
|
+
}
|
|
6356
6785
|
}
|
|
6786
|
+
totals.medianCacheHitRate = median(perEventHitRates);
|
|
6357
6787
|
return totals;
|
|
6358
6788
|
}
|
|
6359
6789
|
async getByModel(range) {
|
|
@@ -6587,6 +7017,15 @@ var NUMERIC_FIELDS = [
|
|
|
6587
7017
|
];
|
|
6588
7018
|
var NULLABLE_STRING_FIELDS = ["messageId", "parentMessageId", "sessionId", "apiKeyId"];
|
|
6589
7019
|
var isStringOrNull = (v) => v === null || typeof v === "string";
|
|
7020
|
+
var CACHE_KEY_SOURCES = /* @__PURE__ */ new Set([
|
|
7021
|
+
"client",
|
|
7022
|
+
"session-header",
|
|
7023
|
+
"thread-header",
|
|
7024
|
+
"body-session-id",
|
|
7025
|
+
"body-thread-id",
|
|
7026
|
+
"content-fingerprint",
|
|
7027
|
+
"none"
|
|
7028
|
+
]);
|
|
6590
7029
|
function isUsageEventRecord(parsed) {
|
|
6591
7030
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return false;
|
|
6592
7031
|
const r = parsed;
|
|
@@ -6594,6 +7033,10 @@ function isUsageEventRecord(parsed) {
|
|
|
6594
7033
|
if (typeof r["providerId"] !== "string") return false;
|
|
6595
7034
|
if (typeof r["model"] !== "string") return false;
|
|
6596
7035
|
if (typeof r["engineOrigin"] !== "string") return false;
|
|
7036
|
+
if (r["cacheKeySource"] !== void 0 && (typeof r["cacheKeySource"] !== "string" || !CACHE_KEY_SOURCES.has(r["cacheKeySource"]))) return false;
|
|
7037
|
+
if (r["cacheKeyInjected"] !== void 0 && typeof r["cacheKeyInjected"] !== "boolean") {
|
|
7038
|
+
return false;
|
|
7039
|
+
}
|
|
6597
7040
|
for (const f of NULLABLE_STRING_FIELDS) {
|
|
6598
7041
|
if (!isStringOrNull(r[f])) return false;
|
|
6599
7042
|
}
|
|
@@ -6603,14 +7046,30 @@ function isUsageEventRecord(parsed) {
|
|
|
6603
7046
|
}
|
|
6604
7047
|
return true;
|
|
6605
7048
|
}
|
|
7049
|
+
function median(values) {
|
|
7050
|
+
if (values.length === 0) return null;
|
|
7051
|
+
values.sort((a, b) => a - b);
|
|
7052
|
+
const middle = Math.floor(values.length / 2);
|
|
7053
|
+
return values.length % 2 === 1 ? values[middle] : (values[middle - 1] + values[middle]) / 2;
|
|
7054
|
+
}
|
|
6606
7055
|
|
|
6607
7056
|
// src/ports/JsonOutboundKeyDb.ts
|
|
6608
7057
|
var import_node_fs11 = require("fs");
|
|
6609
7058
|
var JsonOutboundKeyDb = class {
|
|
6610
|
-
|
|
7059
|
+
/**
|
|
7060
|
+
* @param secretBox OPTIONAL reversible-secret codec. When present, a created
|
|
7061
|
+
* key's plaintext is persisted as a `keySecret` `enc:` envelope (enabling the
|
|
7062
|
+
* operator "view key" affordance via `outboundApiKeysReveal`). When absent the
|
|
7063
|
+
* store stays hash-only (byte-identical to the legacy behavior) and reveal
|
|
7064
|
+
* always returns `null`. Existing 1-arg call sites (tests, lightweight
|
|
7065
|
+
* embedders) keep working.
|
|
7066
|
+
*/
|
|
7067
|
+
constructor(keysPath, secretBox3) {
|
|
6611
7068
|
this.keysPath = keysPath;
|
|
7069
|
+
this.secretBox = secretBox3;
|
|
6612
7070
|
}
|
|
6613
7071
|
keysPath;
|
|
7072
|
+
secretBox;
|
|
6614
7073
|
async outboundApiKeysList() {
|
|
6615
7074
|
return this.readRows();
|
|
6616
7075
|
}
|
|
@@ -6636,10 +7095,27 @@ var JsonOutboundKeyDb = class {
|
|
|
6636
7095
|
allowedEndpoints: input.allowedEndpoints,
|
|
6637
7096
|
loopbackOnly: input.loopbackOnly
|
|
6638
7097
|
};
|
|
7098
|
+
if (input.plaintext && this.secretBox) {
|
|
7099
|
+
row.keySecret = this.secretBox.encrypt(input.plaintext);
|
|
7100
|
+
}
|
|
6639
7101
|
rows.push(row);
|
|
6640
7102
|
this.writeRows(rows);
|
|
6641
7103
|
return row;
|
|
6642
7104
|
}
|
|
7105
|
+
async outboundApiKeysReveal(id) {
|
|
7106
|
+
const rows = this.readRows();
|
|
7107
|
+
const row = rows.find((r) => r.id === id);
|
|
7108
|
+
if (!row || !row.keySecret || !this.secretBox) return null;
|
|
7109
|
+
return this.secretBox.decrypt(row.keySecret);
|
|
7110
|
+
}
|
|
7111
|
+
async outboundApiKeysDelete(id) {
|
|
7112
|
+
const rows = this.readRows();
|
|
7113
|
+
const idx = rows.findIndex((r) => r.id === id);
|
|
7114
|
+
if (idx < 0) return false;
|
|
7115
|
+
rows.splice(idx, 1);
|
|
7116
|
+
this.writeRows(rows);
|
|
7117
|
+
return true;
|
|
7118
|
+
}
|
|
6643
7119
|
async outboundApiKeysRevoke(id) {
|
|
6644
7120
|
return this.mutateRow(id, (row) => {
|
|
6645
7121
|
if (row.revokedAt !== null) return false;
|
|
@@ -7088,7 +7564,7 @@ var JsonVoucherDb = class {
|
|
|
7088
7564
|
|
|
7089
7565
|
// src/ports/JsonSubscriptionCredentialStore.ts
|
|
7090
7566
|
var import_node_fs16 = require("fs");
|
|
7091
|
-
var
|
|
7567
|
+
var import_node_path9 = require("path");
|
|
7092
7568
|
var import_SubscriptionAccountHealth2 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
|
|
7093
7569
|
var import_AccountAllowanceScheduling3 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
|
|
7094
7570
|
var import_upstreamFetch4 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
@@ -7138,10 +7614,10 @@ function findDuplicateCredentialIds(accounts) {
|
|
|
7138
7614
|
|
|
7139
7615
|
// src/ports/external-cli-credentials.ts
|
|
7140
7616
|
var import_node_fs15 = require("fs");
|
|
7141
|
-
var
|
|
7142
|
-
var
|
|
7143
|
-
function externalStorePath(provider, home = (0,
|
|
7144
|
-
return provider === "claude" ? (0,
|
|
7617
|
+
var import_node_os4 = require("os");
|
|
7618
|
+
var import_node_path8 = require("path");
|
|
7619
|
+
function externalStorePath(provider, home = (0, import_node_os4.homedir)()) {
|
|
7620
|
+
return provider === "claude" ? (0, import_node_path8.join)(home, ".claude", ".credentials.json") : (0, import_node_path8.join)(home, ".codex", "auth.json");
|
|
7145
7621
|
}
|
|
7146
7622
|
function decodeJwtExpiryMs(token) {
|
|
7147
7623
|
try {
|
|
@@ -7188,7 +7664,7 @@ function parseCodexTokensEnvelope(raw) {
|
|
|
7188
7664
|
}
|
|
7189
7665
|
return parsed;
|
|
7190
7666
|
}
|
|
7191
|
-
function readExternalCliCredentials(provider, home = (0,
|
|
7667
|
+
function readExternalCliCredentials(provider, home = (0, import_node_os4.homedir)()) {
|
|
7192
7668
|
const path2 = externalStorePath(provider, home);
|
|
7193
7669
|
if (!(0, import_node_fs15.existsSync)(path2)) return null;
|
|
7194
7670
|
let raw;
|
|
@@ -7231,9 +7707,15 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
7231
7707
|
* TEST-injected `fetchImpl` is returned verbatim; otherwise the refresh routes
|
|
7232
7708
|
* through {@link fetchUpstream} with the account's `{ providerId, accountId }`
|
|
7233
7709
|
* ctx so the per-account/provider proxy applies. `@internal` also a test seam.
|
|
7710
|
+
*
|
|
7711
|
+
* `redactBodies` is REQUIRED here: this round-trip sends the refresh_token and
|
|
7712
|
+
* receives a fresh access/refresh token pair. Carrying a `providerId` opts the
|
|
7713
|
+
* call into the upstream trace (so a failing refresh is diagnosable), and the
|
|
7714
|
+
* trace captures bodies verbatim — without this flag every refresh would write
|
|
7715
|
+
* a plaintext token pair into `upstream-trace.jsonl`.
|
|
7234
7716
|
*/
|
|
7235
7717
|
buildRefreshFetch(providerId, accountId) {
|
|
7236
|
-
return this.fetchImpl ?? ((url, init) => (0, import_upstreamFetch4.fetchUpstream)(url, init, { providerId, accountId }));
|
|
7718
|
+
return this.fetchImpl ?? ((url, init) => (0, import_upstreamFetch4.fetchUpstream)(url, init, { providerId, accountId, redactBodies: true }));
|
|
7237
7719
|
}
|
|
7238
7720
|
/**
|
|
7239
7721
|
* In-flight refresh coalescing. OAuth refresh tokens are
|
|
@@ -7758,7 +8240,7 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
7758
8240
|
* `enc:v1:`; already-`enc:`/`$ENV` untouched) before serializing, so any
|
|
7759
8241
|
* write incl. child 4's future refresh writes lands encrypted. */
|
|
7760
8242
|
persist(config) {
|
|
7761
|
-
(0, import_node_fs16.mkdirSync)((0,
|
|
8243
|
+
(0, import_node_fs16.mkdirSync)((0, import_node_path9.dirname)(this.tokensPath), { recursive: true });
|
|
7762
8244
|
const encrypted = encryptTokens(config, this.box);
|
|
7763
8245
|
(0, import_node_fs16.writeFileSync)(this.tokensPath, JSON.stringify(encrypted, null, 2) + "\n", "utf8");
|
|
7764
8246
|
}
|
|
@@ -7793,6 +8275,124 @@ var JsonSubscriptionCredentialStore = class {
|
|
|
7793
8275
|
// src/AccountHealthProbeScheduler.ts
|
|
7794
8276
|
var import_upstreamFetch5 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
7795
8277
|
|
|
8278
|
+
// src/probe/CodexGenerationProbe.ts
|
|
8279
|
+
var import_codexCliHeaders = require("@omnicross/core/provider-proxy/identity/codexCliHeaders");
|
|
8280
|
+
var CODEX_GENERATION_PROBE_MODEL = "gpt-5.6-luna";
|
|
8281
|
+
var CODEX_GENERATION_PROBE_URL = "https://chatgpt.com/backend-api/codex/responses";
|
|
8282
|
+
var MAX_STREAM_BYTES = 256 * 1024;
|
|
8283
|
+
var PROBE_INSTRUCTION = "Return exactly PONG and no other text.";
|
|
8284
|
+
function buildCodexGenerationProbeInit(token, signal) {
|
|
8285
|
+
return {
|
|
8286
|
+
method: "POST",
|
|
8287
|
+
signal,
|
|
8288
|
+
headers: {
|
|
8289
|
+
...import_codexCliHeaders.DEFAULT_CODEX_CLI_HEADERS,
|
|
8290
|
+
Authorization: `Bearer ${token}`,
|
|
8291
|
+
Accept: (0, import_codexCliHeaders.codexAcceptHeader)(true),
|
|
8292
|
+
"Content-Type": "application/json"
|
|
8293
|
+
},
|
|
8294
|
+
body: JSON.stringify({
|
|
8295
|
+
model: CODEX_GENERATION_PROBE_MODEL,
|
|
8296
|
+
input: [
|
|
8297
|
+
{
|
|
8298
|
+
role: "developer",
|
|
8299
|
+
content: [{ type: "input_text", text: PROBE_INSTRUCTION }]
|
|
8300
|
+
},
|
|
8301
|
+
{
|
|
8302
|
+
role: "user",
|
|
8303
|
+
content: [{ type: "input_text", text: "Connection probe." }]
|
|
8304
|
+
}
|
|
8305
|
+
],
|
|
8306
|
+
// GPT-5.6 otherwise defaults to medium reasoning. A connectivity probe
|
|
8307
|
+
// needs the lowest-cost path and no tool reasoning.
|
|
8308
|
+
reasoning: { effort: "none" },
|
|
8309
|
+
stream: true,
|
|
8310
|
+
store: false
|
|
8311
|
+
})
|
|
8312
|
+
};
|
|
8313
|
+
}
|
|
8314
|
+
async function readCodexGenerationProbeStream(response) {
|
|
8315
|
+
if (!response.body) return { completed: false, outputChars: 0 };
|
|
8316
|
+
const reader = response.body.getReader();
|
|
8317
|
+
const decoder = new TextDecoder();
|
|
8318
|
+
let buffer = "";
|
|
8319
|
+
let bytes = 0;
|
|
8320
|
+
let outputChars = 0;
|
|
8321
|
+
try {
|
|
8322
|
+
while (true) {
|
|
8323
|
+
const { done, value } = await reader.read();
|
|
8324
|
+
if (done) break;
|
|
8325
|
+
bytes += value.byteLength;
|
|
8326
|
+
if (bytes > MAX_STREAM_BYTES) {
|
|
8327
|
+
await reader.cancel();
|
|
8328
|
+
return { completed: false, outputChars };
|
|
8329
|
+
}
|
|
8330
|
+
buffer += decoder.decode(value, { stream: true });
|
|
8331
|
+
buffer = buffer.replace(/\r\n/g, "\n");
|
|
8332
|
+
let boundary = buffer.indexOf("\n\n");
|
|
8333
|
+
while (boundary >= 0) {
|
|
8334
|
+
const block = buffer.slice(0, boundary);
|
|
8335
|
+
buffer = buffer.slice(boundary + 2);
|
|
8336
|
+
const event = parseSseBlock(block);
|
|
8337
|
+
if (event) {
|
|
8338
|
+
const type = event["type"];
|
|
8339
|
+
if (type === "response.output_text.delta" && typeof event["delta"] === "string") {
|
|
8340
|
+
outputChars += event["delta"].length;
|
|
8341
|
+
} else if (type === "response.output_text.done" && typeof event["text"] === "string") {
|
|
8342
|
+
outputChars = Math.max(outputChars, event["text"].length);
|
|
8343
|
+
} else if (type === "response.failed" || type === "error") {
|
|
8344
|
+
await reader.cancel();
|
|
8345
|
+
return { completed: false, outputChars };
|
|
8346
|
+
} else if (type === "response.completed") {
|
|
8347
|
+
const completedResponse = asRecord(event["response"]);
|
|
8348
|
+
const status = completedResponse?.["status"];
|
|
8349
|
+
outputChars = Math.max(outputChars, countCompletedOutputChars(completedResponse));
|
|
8350
|
+
await reader.cancel();
|
|
8351
|
+
return {
|
|
8352
|
+
completed: (status === void 0 || status === "completed") && outputChars > 0,
|
|
8353
|
+
outputChars
|
|
8354
|
+
};
|
|
8355
|
+
}
|
|
8356
|
+
}
|
|
8357
|
+
boundary = buffer.indexOf("\n\n");
|
|
8358
|
+
}
|
|
8359
|
+
}
|
|
8360
|
+
} catch {
|
|
8361
|
+
return { completed: false, outputChars };
|
|
8362
|
+
} finally {
|
|
8363
|
+
reader.releaseLock();
|
|
8364
|
+
}
|
|
8365
|
+
return { completed: false, outputChars };
|
|
8366
|
+
}
|
|
8367
|
+
function parseSseBlock(block) {
|
|
8368
|
+
const data = block.split("\n").filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trimStart()).join("\n");
|
|
8369
|
+
if (!data || data === "[DONE]") return null;
|
|
8370
|
+
try {
|
|
8371
|
+
return JSON.parse(data);
|
|
8372
|
+
} catch {
|
|
8373
|
+
return null;
|
|
8374
|
+
}
|
|
8375
|
+
}
|
|
8376
|
+
function asRecord(value) {
|
|
8377
|
+
return value !== null && typeof value === "object" ? value : void 0;
|
|
8378
|
+
}
|
|
8379
|
+
function countCompletedOutputChars(response) {
|
|
8380
|
+
const output = response?.["output"];
|
|
8381
|
+
if (!Array.isArray(output)) return 0;
|
|
8382
|
+
let chars = 0;
|
|
8383
|
+
for (const item of output) {
|
|
8384
|
+
const content = asRecord(item)?.["content"];
|
|
8385
|
+
if (!Array.isArray(content)) continue;
|
|
8386
|
+
for (const part of content) {
|
|
8387
|
+
const record = asRecord(part);
|
|
8388
|
+
if (record?.["type"] === "output_text" && typeof record["text"] === "string") {
|
|
8389
|
+
chars += record["text"].length;
|
|
8390
|
+
}
|
|
8391
|
+
}
|
|
8392
|
+
}
|
|
8393
|
+
return chars;
|
|
8394
|
+
}
|
|
8395
|
+
|
|
7796
8396
|
// src/probe/ProbeStrategy.ts
|
|
7797
8397
|
var PROVIDER_PROBE_PLANS = {
|
|
7798
8398
|
claude: {
|
|
@@ -7920,17 +8520,17 @@ var AccountHealthProbeScheduler = class {
|
|
|
7920
8520
|
}
|
|
7921
8521
|
if (readThrew) {
|
|
7922
8522
|
this.record(providerId, accountId, { ts: now, ok: false, status: null, tier: "local" });
|
|
7923
|
-
return { ok: false, marked: false };
|
|
8523
|
+
return { ok: false, marked: false, tier: "local" };
|
|
7924
8524
|
}
|
|
7925
8525
|
if (!token) {
|
|
7926
8526
|
this.health.recordUpstreamOutcome(providerId, accountId, { status: 401, now });
|
|
7927
8527
|
this.record(providerId, accountId, { ts: now, ok: false, status: 401, tier: "local" });
|
|
7928
|
-
return { ok: false, marked: true };
|
|
8528
|
+
return { ok: false, marked: true, tier: "local" };
|
|
7929
8529
|
}
|
|
7930
8530
|
const plan = this.planFor(providerId);
|
|
7931
8531
|
if (plan.kind === "local") {
|
|
7932
8532
|
this.record(providerId, accountId, { ts: now, ok: true, tier: "local" });
|
|
7933
|
-
return { ok: true, marked: false };
|
|
8533
|
+
return { ok: true, marked: false, tier: "local" };
|
|
7934
8534
|
}
|
|
7935
8535
|
const start = this.now();
|
|
7936
8536
|
let status = null;
|
|
@@ -7955,7 +8555,60 @@ var AccountHealthProbeScheduler = class {
|
|
|
7955
8555
|
latencyMs,
|
|
7956
8556
|
tier: "upstream"
|
|
7957
8557
|
});
|
|
7958
|
-
return { ok: status !== null && status < 400, marked };
|
|
8558
|
+
return { ok: status !== null && status < 400, marked, tier: "upstream" };
|
|
8559
|
+
}
|
|
8560
|
+
/**
|
|
8561
|
+
* Manual connection test. Codex performs a real, quota-consuming generation;
|
|
8562
|
+
* every other provider keeps its existing cheap probe. Scheduled sweeps never
|
|
8563
|
+
* call this method, so they remain non-billable.
|
|
8564
|
+
*/
|
|
8565
|
+
async testAccountConnection(providerId, accountId) {
|
|
8566
|
+
if (providerId !== "codex") return this.probeAccount(providerId, accountId);
|
|
8567
|
+
const now = this.now();
|
|
8568
|
+
let token;
|
|
8569
|
+
try {
|
|
8570
|
+
token = await this.store.getAccessTokenForAccount(providerId, accountId);
|
|
8571
|
+
} catch {
|
|
8572
|
+
this.record(providerId, accountId, { ts: now, ok: false, status: null, tier: "local" });
|
|
8573
|
+
return { ok: false, marked: false, tier: "local", model: CODEX_GENERATION_PROBE_MODEL };
|
|
8574
|
+
}
|
|
8575
|
+
if (!token) {
|
|
8576
|
+
this.health.recordUpstreamOutcome(providerId, accountId, { status: 401, now });
|
|
8577
|
+
this.record(providerId, accountId, { ts: now, ok: false, status: 401, tier: "local" });
|
|
8578
|
+
return { ok: false, marked: true, tier: "local", model: CODEX_GENERATION_PROBE_MODEL };
|
|
8579
|
+
}
|
|
8580
|
+
const startedAt = this.now();
|
|
8581
|
+
let attempt = await this.runCodexGenerationAttempt(accountId, token);
|
|
8582
|
+
if (attempt.status === 401 && this.store.refreshAccountToken) {
|
|
8583
|
+
try {
|
|
8584
|
+
if (await this.store.refreshAccountToken(providerId, accountId)) {
|
|
8585
|
+
const refreshed = await this.store.getAccessTokenForAccount(providerId, accountId);
|
|
8586
|
+
if (refreshed) attempt = await this.runCodexGenerationAttempt(accountId, refreshed);
|
|
8587
|
+
}
|
|
8588
|
+
} catch {
|
|
8589
|
+
}
|
|
8590
|
+
}
|
|
8591
|
+
const latencyMs = this.now() - startedAt;
|
|
8592
|
+
const ok = attempt.status !== null && attempt.status >= 200 && attempt.status < 300 && attempt.completed;
|
|
8593
|
+
let marked = false;
|
|
8594
|
+
if (ok) {
|
|
8595
|
+
this.health.clearTransientMark(providerId, accountId);
|
|
8596
|
+
} else if (attempt.status === 401 || attempt.status === 403) {
|
|
8597
|
+
marked = this.applyOutcome(providerId, accountId, attempt.status, attempt.bodyText, now);
|
|
8598
|
+
}
|
|
8599
|
+
this.record(providerId, accountId, {
|
|
8600
|
+
ts: now,
|
|
8601
|
+
ok,
|
|
8602
|
+
status: attempt.status,
|
|
8603
|
+
latencyMs,
|
|
8604
|
+
tier: "generation"
|
|
8605
|
+
});
|
|
8606
|
+
return {
|
|
8607
|
+
ok,
|
|
8608
|
+
marked,
|
|
8609
|
+
tier: "generation",
|
|
8610
|
+
model: CODEX_GENERATION_PROBE_MODEL
|
|
8611
|
+
};
|
|
7959
8612
|
}
|
|
7960
8613
|
/** Per-account rolling history for the authed admin surface (design D5). */
|
|
7961
8614
|
getAllHistory() {
|
|
@@ -8012,6 +8665,24 @@ var AccountHealthProbeScheduler = class {
|
|
|
8012
8665
|
return "";
|
|
8013
8666
|
}
|
|
8014
8667
|
}
|
|
8668
|
+
async runCodexGenerationAttempt(accountId, token) {
|
|
8669
|
+
try {
|
|
8670
|
+
const timeoutMs = Math.max(this.config.timeoutMs, 15e3);
|
|
8671
|
+
const response = await this.fetchImpl(
|
|
8672
|
+
CODEX_GENERATION_PROBE_URL,
|
|
8673
|
+
buildCodexGenerationProbeInit(token, AbortSignal.timeout(timeoutMs)),
|
|
8674
|
+
{ providerId: "codex", accountId, redactBodies: true }
|
|
8675
|
+
);
|
|
8676
|
+
if (response.status < 200 || response.status >= 300) {
|
|
8677
|
+
const bodyText = response.status === 403 ? await this.readBounded(response) : void 0;
|
|
8678
|
+
return { status: response.status, completed: false, bodyText };
|
|
8679
|
+
}
|
|
8680
|
+
const stream = await readCodexGenerationProbeStream(response);
|
|
8681
|
+
return { status: response.status, completed: stream.completed };
|
|
8682
|
+
} catch {
|
|
8683
|
+
return { status: null, completed: false };
|
|
8684
|
+
}
|
|
8685
|
+
}
|
|
8015
8686
|
key(providerId, accountId) {
|
|
8016
8687
|
return `${providerId}${KEY_SEP}${accountId}`;
|
|
8017
8688
|
}
|
|
@@ -8107,7 +8778,7 @@ var AccountHealthSweeper = class {
|
|
|
8107
8778
|
};
|
|
8108
8779
|
|
|
8109
8780
|
// src/audit/AuditPruneSweeper.ts
|
|
8110
|
-
var
|
|
8781
|
+
var import_node_fs18 = require("fs");
|
|
8111
8782
|
var import_node_path11 = require("path");
|
|
8112
8783
|
|
|
8113
8784
|
// src/audit/auditFiles.ts
|
|
@@ -8130,12 +8801,206 @@ function auditFileDateMs(fileName) {
|
|
|
8130
8801
|
return d.getTime();
|
|
8131
8802
|
}
|
|
8132
8803
|
|
|
8804
|
+
// src/audit/auditStats.ts
|
|
8805
|
+
var import_node_fs17 = require("fs");
|
|
8806
|
+
var import_node_path10 = require("path");
|
|
8807
|
+
var SIDECAR_VERSION = 1;
|
|
8808
|
+
var META_PREFIX_BYTES = 64 * 1024;
|
|
8809
|
+
var READ_CHUNK_BYTES = 4 * 1024 * 1024;
|
|
8810
|
+
function auditStatsFileName(auditFile) {
|
|
8811
|
+
return auditFile.replace(/\.jsonl$/, ".stats.json");
|
|
8812
|
+
}
|
|
8813
|
+
function readPersisted(path2) {
|
|
8814
|
+
if (!(0, import_node_fs17.existsSync)(path2)) return null;
|
|
8815
|
+
try {
|
|
8816
|
+
const value = JSON.parse((0, import_node_fs17.readFileSync)(path2, "utf8"));
|
|
8817
|
+
if (value.version !== SIDECAR_VERSION || !Number.isSafeInteger(value.auditBytes) || (value.auditBytes ?? -1) < 0 || !Number.isSafeInteger(value.requestCount) || (value.requestCount ?? -1) < 0 || !Number.isSafeInteger(value.errorCount) || (value.errorCount ?? -1) < 0 || (value.errorCount ?? 0) > (value.requestCount ?? -1) || typeof value.complete !== "boolean" || value.minTs !== null && !Number.isFinite(value.minTs) || value.maxTs !== null && !Number.isFinite(value.maxTs)) {
|
|
8818
|
+
return null;
|
|
8819
|
+
}
|
|
8820
|
+
return value;
|
|
8821
|
+
} catch {
|
|
8822
|
+
return null;
|
|
8823
|
+
}
|
|
8824
|
+
}
|
|
8825
|
+
function updateAuditStatsAfterAppend(auditPath, auditBytesBefore, auditBytesAfter, record) {
|
|
8826
|
+
const statsPath = (0, import_node_path10.join)((0, import_node_path10.dirname)(auditPath), auditStatsFileName((0, import_node_path10.basename)(auditPath)));
|
|
8827
|
+
const previous = auditBytesBefore === 0 ? {
|
|
8828
|
+
version: SIDECAR_VERSION,
|
|
8829
|
+
auditBytes: 0,
|
|
8830
|
+
requestCount: 0,
|
|
8831
|
+
errorCount: 0,
|
|
8832
|
+
complete: true,
|
|
8833
|
+
minTs: null,
|
|
8834
|
+
maxTs: null
|
|
8835
|
+
} : readPersisted(statsPath);
|
|
8836
|
+
if (!previous || !previous.complete || previous.auditBytes !== auditBytesBefore) return;
|
|
8837
|
+
const next = {
|
|
8838
|
+
version: SIDECAR_VERSION,
|
|
8839
|
+
auditBytes: auditBytesAfter,
|
|
8840
|
+
requestCount: previous.requestCount + 1,
|
|
8841
|
+
errorCount: previous.errorCount + (record.status >= 400 || Boolean(record.error) ? 1 : 0),
|
|
8842
|
+
complete: true,
|
|
8843
|
+
minTs: previous.minTs === null ? record.ts : Math.min(previous.minTs, record.ts),
|
|
8844
|
+
maxTs: previous.maxTs === null ? record.ts : Math.max(previous.maxTs, record.ts)
|
|
8845
|
+
};
|
|
8846
|
+
(0, import_node_fs17.writeFileSync)(statsPath, JSON.stringify(next), "utf8");
|
|
8847
|
+
}
|
|
8848
|
+
function queryCovers(stats, from, to) {
|
|
8849
|
+
return stats.requestCount === 0 || stats.minTs !== null && stats.maxTs !== null && from <= stats.minTs && to >= stats.maxTs;
|
|
8850
|
+
}
|
|
8851
|
+
function fileOverlaps(file, from, to) {
|
|
8852
|
+
const start = auditFileDateMs(file);
|
|
8853
|
+
if (start === null) return false;
|
|
8854
|
+
const date = new Date(start);
|
|
8855
|
+
const end = new Date(date.getFullYear(), date.getMonth(), date.getDate() + 1).getTime();
|
|
8856
|
+
return end > from && start <= to;
|
|
8857
|
+
}
|
|
8858
|
+
function parseMetadataPrefix(prefix, prefixTruncated) {
|
|
8859
|
+
const text = prefix.toString("utf8");
|
|
8860
|
+
const tsMatch = /(?:^|,)"ts":(-?\d+)/.exec(text);
|
|
8861
|
+
const statusMatch = /(?:^|,)"status":(-?\d+)/.exec(text);
|
|
8862
|
+
const errorMatch = /(?:^|,)"error":"((?:\\.|[^"\\])*)"/.exec(text);
|
|
8863
|
+
const bodyStarted = /,(?:"requestBody"|"responseBody"):/.test(text);
|
|
8864
|
+
return {
|
|
8865
|
+
ts: tsMatch ? Number(tsMatch[1]) : void 0,
|
|
8866
|
+
status: statusMatch ? Number(statusMatch[1]) : void 0,
|
|
8867
|
+
hasError: Boolean(errorMatch?.[1]),
|
|
8868
|
+
complete: Boolean(tsMatch && statusMatch && (!prefixTruncated || bodyStarted))
|
|
8869
|
+
};
|
|
8870
|
+
}
|
|
8871
|
+
async function scanAuditFile(auditPath, startByte, auditBytes, from, to) {
|
|
8872
|
+
let requestCount = 0;
|
|
8873
|
+
let errorCount = 0;
|
|
8874
|
+
let filteredRequestCount = 0;
|
|
8875
|
+
let filteredErrorCount = 0;
|
|
8876
|
+
let minTs = null;
|
|
8877
|
+
let maxTs = null;
|
|
8878
|
+
let complete = true;
|
|
8879
|
+
let prefixParts = [];
|
|
8880
|
+
let prefixBytes = 0;
|
|
8881
|
+
let prefixTruncated = false;
|
|
8882
|
+
const consumeLine = () => {
|
|
8883
|
+
if (prefixBytes === 0 && !prefixTruncated) return;
|
|
8884
|
+
const prefix = Buffer.concat(prefixParts, prefixBytes);
|
|
8885
|
+
const metadata = parseMetadataPrefix(prefix, prefixTruncated);
|
|
8886
|
+
if (!metadata.complete || metadata.ts === void 0 || metadata.status === void 0) {
|
|
8887
|
+
complete = false;
|
|
8888
|
+
} else {
|
|
8889
|
+
requestCount += 1;
|
|
8890
|
+
const isError = metadata.status >= 400 || metadata.hasError;
|
|
8891
|
+
if (isError) errorCount += 1;
|
|
8892
|
+
minTs = minTs === null ? metadata.ts : Math.min(minTs, metadata.ts);
|
|
8893
|
+
maxTs = maxTs === null ? metadata.ts : Math.max(maxTs, metadata.ts);
|
|
8894
|
+
if (metadata.ts >= from && metadata.ts <= to) {
|
|
8895
|
+
filteredRequestCount += 1;
|
|
8896
|
+
if (isError) filteredErrorCount += 1;
|
|
8897
|
+
}
|
|
8898
|
+
}
|
|
8899
|
+
prefixParts = [];
|
|
8900
|
+
prefixBytes = 0;
|
|
8901
|
+
prefixTruncated = false;
|
|
8902
|
+
};
|
|
8903
|
+
if (auditBytes > startByte) {
|
|
8904
|
+
const stream = (0, import_node_fs17.createReadStream)(auditPath, {
|
|
8905
|
+
start: startByte,
|
|
8906
|
+
end: auditBytes - 1,
|
|
8907
|
+
highWaterMark: READ_CHUNK_BYTES
|
|
8908
|
+
});
|
|
8909
|
+
for await (const value of stream) {
|
|
8910
|
+
const chunk = Buffer.isBuffer(value) ? value : Buffer.from(value);
|
|
8911
|
+
let offset = 0;
|
|
8912
|
+
while (offset < chunk.length) {
|
|
8913
|
+
const newline = chunk.indexOf(10, offset);
|
|
8914
|
+
const end = newline === -1 ? chunk.length : newline;
|
|
8915
|
+
if (prefixBytes < META_PREFIX_BYTES) {
|
|
8916
|
+
const retained = Math.min(META_PREFIX_BYTES - prefixBytes, end - offset);
|
|
8917
|
+
if (retained > 0) {
|
|
8918
|
+
prefixParts.push(Buffer.from(chunk.subarray(offset, offset + retained)));
|
|
8919
|
+
prefixBytes += retained;
|
|
8920
|
+
}
|
|
8921
|
+
if (retained < end - offset) prefixTruncated = true;
|
|
8922
|
+
} else if (end > offset) {
|
|
8923
|
+
prefixTruncated = true;
|
|
8924
|
+
}
|
|
8925
|
+
if (newline === -1) break;
|
|
8926
|
+
consumeLine();
|
|
8927
|
+
offset = newline + 1;
|
|
8928
|
+
}
|
|
8929
|
+
}
|
|
8930
|
+
}
|
|
8931
|
+
if (prefixBytes > 0 || prefixTruncated) complete = false;
|
|
8932
|
+
return {
|
|
8933
|
+
all: {
|
|
8934
|
+
version: SIDECAR_VERSION,
|
|
8935
|
+
auditBytes,
|
|
8936
|
+
requestCount,
|
|
8937
|
+
errorCount,
|
|
8938
|
+
complete,
|
|
8939
|
+
minTs,
|
|
8940
|
+
maxTs
|
|
8941
|
+
},
|
|
8942
|
+
filtered: { requestCount: filteredRequestCount, errorCount: filteredErrorCount, complete }
|
|
8943
|
+
};
|
|
8944
|
+
}
|
|
8945
|
+
function mergePersistedStats(previous, appended) {
|
|
8946
|
+
return {
|
|
8947
|
+
version: SIDECAR_VERSION,
|
|
8948
|
+
auditBytes: appended.auditBytes,
|
|
8949
|
+
requestCount: previous.requestCount + appended.requestCount,
|
|
8950
|
+
errorCount: previous.errorCount + appended.errorCount,
|
|
8951
|
+
complete: previous.complete && appended.complete,
|
|
8952
|
+
minTs: previous.minTs === null ? appended.minTs : appended.minTs === null ? previous.minTs : Math.min(previous.minTs, appended.minTs),
|
|
8953
|
+
maxTs: previous.maxTs === null ? appended.maxTs : appended.maxTs === null ? previous.maxTs : Math.max(previous.maxTs, appended.maxTs)
|
|
8954
|
+
};
|
|
8955
|
+
}
|
|
8956
|
+
async function readAuditStats(auditDir, query2 = {}) {
|
|
8957
|
+
if (!(0, import_node_fs17.existsSync)(auditDir)) return { requestCount: 0, errorCount: 0, complete: true };
|
|
8958
|
+
const from = typeof query2.from === "number" ? query2.from : -Infinity;
|
|
8959
|
+
const to = typeof query2.to === "number" ? query2.to : Infinity;
|
|
8960
|
+
let files;
|
|
8961
|
+
try {
|
|
8962
|
+
files = (0, import_node_fs17.readdirSync)(auditDir).filter((file) => AUDIT_FILE_RE.test(file) && fileOverlaps(file, from, to)).sort();
|
|
8963
|
+
} catch {
|
|
8964
|
+
return { requestCount: 0, errorCount: 0, complete: false };
|
|
8965
|
+
}
|
|
8966
|
+
const total = { requestCount: 0, errorCount: 0, complete: true };
|
|
8967
|
+
for (const file of files) {
|
|
8968
|
+
const auditPath = (0, import_node_path10.join)(auditDir, file);
|
|
8969
|
+
try {
|
|
8970
|
+
const auditBytes = (0, import_node_fs17.statSync)(auditPath).size;
|
|
8971
|
+
const statsPath = (0, import_node_path10.join)(auditDir, auditStatsFileName(file));
|
|
8972
|
+
const persisted = readPersisted(statsPath);
|
|
8973
|
+
if (persisted && persisted.complete && persisted.auditBytes === auditBytes && queryCovers(persisted, from, to)) {
|
|
8974
|
+
total.requestCount += persisted.requestCount;
|
|
8975
|
+
total.errorCount += persisted.errorCount;
|
|
8976
|
+
continue;
|
|
8977
|
+
}
|
|
8978
|
+
const resumable = persisted && persisted.complete && persisted.auditBytes < auditBytes && queryCovers(persisted, from, to) ? persisted : null;
|
|
8979
|
+
const scanned = await scanAuditFile(
|
|
8980
|
+
auditPath,
|
|
8981
|
+
resumable?.auditBytes ?? 0,
|
|
8982
|
+
auditBytes,
|
|
8983
|
+
from,
|
|
8984
|
+
to
|
|
8985
|
+
);
|
|
8986
|
+
total.requestCount += scanned.filtered.requestCount + (resumable?.requestCount ?? 0);
|
|
8987
|
+
total.errorCount += scanned.filtered.errorCount + (resumable?.errorCount ?? 0);
|
|
8988
|
+
total.complete = total.complete && scanned.filtered.complete;
|
|
8989
|
+
const current = resumable ? mergePersistedStats(resumable, scanned.all) : scanned.all;
|
|
8990
|
+
if (current.complete) (0, import_node_fs17.writeFileSync)(statsPath, JSON.stringify(current), "utf8");
|
|
8991
|
+
} catch {
|
|
8992
|
+
total.complete = false;
|
|
8993
|
+
}
|
|
8994
|
+
}
|
|
8995
|
+
return total;
|
|
8996
|
+
}
|
|
8997
|
+
|
|
8133
8998
|
// src/audit/AuditPruneSweeper.ts
|
|
8134
8999
|
var DAY_MS = 24 * 60 * 6e4;
|
|
8135
9000
|
var SWEEP_INTERVAL_MS2 = 60 * 6e4;
|
|
8136
9001
|
var AuditPruneSweeper = class {
|
|
8137
|
-
constructor(
|
|
8138
|
-
this.auditDir =
|
|
9002
|
+
constructor(auditDir, logger, config, intervalMs = SWEEP_INTERVAL_MS2, now = Date.now) {
|
|
9003
|
+
this.auditDir = auditDir;
|
|
8139
9004
|
this.logger = logger;
|
|
8140
9005
|
this.config = config;
|
|
8141
9006
|
this.intervalMs = intervalMs;
|
|
@@ -8182,17 +9047,19 @@ var AuditPruneSweeper = class {
|
|
|
8182
9047
|
if (!this.config.enabled || this.sweeping) return 0;
|
|
8183
9048
|
this.sweeping = true;
|
|
8184
9049
|
try {
|
|
8185
|
-
if (!(0,
|
|
9050
|
+
if (!(0, import_node_fs18.existsSync)(this.auditDir)) return 0;
|
|
8186
9051
|
const today = new Date(this.now());
|
|
8187
9052
|
const todayMidnight = new Date(today.getFullYear(), today.getMonth(), today.getDate()).getTime();
|
|
8188
9053
|
const cutoff = todayMidnight - (this.config.retentionDays - 1) * DAY_MS;
|
|
8189
9054
|
let removed = 0;
|
|
8190
|
-
for (const file of (0,
|
|
9055
|
+
for (const file of (0, import_node_fs18.readdirSync)(this.auditDir)) {
|
|
8191
9056
|
const dateMs = auditFileDateMs(file);
|
|
8192
9057
|
if (dateMs === null || dateMs >= cutoff) continue;
|
|
8193
9058
|
try {
|
|
8194
|
-
(0,
|
|
9059
|
+
(0, import_node_fs18.unlinkSync)((0, import_node_path11.join)(this.auditDir, file));
|
|
8195
9060
|
removed += 1;
|
|
9061
|
+
const statsPath = (0, import_node_path11.join)(this.auditDir, auditStatsFileName(file));
|
|
9062
|
+
if ((0, import_node_fs18.existsSync)(statsPath)) (0, import_node_fs18.unlinkSync)(statsPath);
|
|
8196
9063
|
} catch (error) {
|
|
8197
9064
|
this.logger.warn("[AuditPruneSweeper] failed to unlink expired audit file", {
|
|
8198
9065
|
file,
|
|
@@ -8214,15 +9081,15 @@ var AuditPruneSweeper = class {
|
|
|
8214
9081
|
};
|
|
8215
9082
|
|
|
8216
9083
|
// src/audit/auditReader.ts
|
|
8217
|
-
var
|
|
9084
|
+
var import_node_fs19 = require("fs");
|
|
8218
9085
|
var import_node_path12 = require("path");
|
|
8219
9086
|
var DEFAULT_LIMIT = 200;
|
|
8220
9087
|
var MAX_LIMIT = 2e3;
|
|
8221
|
-
function readAuditRecords(
|
|
8222
|
-
if (!(0,
|
|
9088
|
+
function readAuditRecords(auditDir, query2 = {}) {
|
|
9089
|
+
if (!(0, import_node_fs19.existsSync)(auditDir)) return [];
|
|
8223
9090
|
let files;
|
|
8224
9091
|
try {
|
|
8225
|
-
files = (0,
|
|
9092
|
+
files = (0, import_node_fs19.readdirSync)(auditDir).filter((f) => AUDIT_FILE_RE.test(f));
|
|
8226
9093
|
} catch {
|
|
8227
9094
|
return [];
|
|
8228
9095
|
}
|
|
@@ -8233,7 +9100,7 @@ function readAuditRecords(auditDir2, query2 = {}) {
|
|
|
8233
9100
|
for (const file of files.sort().reverse()) {
|
|
8234
9101
|
let raw;
|
|
8235
9102
|
try {
|
|
8236
|
-
raw = (0,
|
|
9103
|
+
raw = (0, import_node_fs19.readFileSync)((0, import_node_path12.join)(auditDir, file), "utf8");
|
|
8237
9104
|
} catch {
|
|
8238
9105
|
continue;
|
|
8239
9106
|
}
|
|
@@ -8262,11 +9129,11 @@ function isAuditRecord(value) {
|
|
|
8262
9129
|
}
|
|
8263
9130
|
|
|
8264
9131
|
// src/audit/AuditWriter.ts
|
|
8265
|
-
var
|
|
9132
|
+
var import_node_fs20 = require("fs");
|
|
8266
9133
|
var import_node_path13 = require("path");
|
|
8267
9134
|
var AuditWriter = class {
|
|
8268
|
-
constructor(
|
|
8269
|
-
this.auditDir =
|
|
9135
|
+
constructor(auditDir, logger, defer = (fn) => setTimeout(fn, 0)) {
|
|
9136
|
+
this.auditDir = auditDir;
|
|
8270
9137
|
this.logger = logger;
|
|
8271
9138
|
this.defer = defer;
|
|
8272
9139
|
}
|
|
@@ -8296,16 +9163,30 @@ var AuditWriter = class {
|
|
|
8296
9163
|
*/
|
|
8297
9164
|
appendNow(record) {
|
|
8298
9165
|
if (!this.dirEnsured) {
|
|
8299
|
-
(0,
|
|
9166
|
+
(0, import_node_fs20.mkdirSync)(this.auditDir, { recursive: true });
|
|
8300
9167
|
this.dirEnsured = true;
|
|
8301
9168
|
}
|
|
8302
9169
|
const file = (0, import_node_path13.join)(this.auditDir, auditFileName(record.ts));
|
|
8303
|
-
|
|
9170
|
+
const line = JSON.stringify(record) + "\n";
|
|
9171
|
+
const auditBytesBefore = (0, import_node_fs20.existsSync)(file) ? (0, import_node_fs20.statSync)(file).size : 0;
|
|
9172
|
+
(0, import_node_fs20.appendFileSync)(file, line, "utf8");
|
|
9173
|
+
try {
|
|
9174
|
+
updateAuditStatsAfterAppend(
|
|
9175
|
+
file,
|
|
9176
|
+
auditBytesBefore,
|
|
9177
|
+
auditBytesBefore + Buffer.byteLength(line, "utf8"),
|
|
9178
|
+
record
|
|
9179
|
+
);
|
|
9180
|
+
} catch (error) {
|
|
9181
|
+
this.logger.warn("[AuditWriter] failed to update audit stats", {
|
|
9182
|
+
error: error instanceof Error ? error.message : String(error)
|
|
9183
|
+
});
|
|
9184
|
+
}
|
|
8304
9185
|
}
|
|
8305
9186
|
};
|
|
8306
9187
|
|
|
8307
9188
|
// src/billing/BillingPublisher.ts
|
|
8308
|
-
var
|
|
9189
|
+
var import_node_fs21 = require("fs");
|
|
8309
9190
|
var import_node_crypto13 = require("crypto");
|
|
8310
9191
|
var import_node_path14 = require("path");
|
|
8311
9192
|
var import_upstreamFetch6 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
@@ -8379,7 +9260,7 @@ var BillingPublisher = class {
|
|
|
8379
9260
|
appendNow(event) {
|
|
8380
9261
|
this.ensureDir();
|
|
8381
9262
|
const file = (0, import_node_path14.join)(this.billingDir, billingFileName(event.ts));
|
|
8382
|
-
(0,
|
|
9263
|
+
(0, import_node_fs21.appendFileSync)(file, JSON.stringify(event) + "\n", "utf8");
|
|
8383
9264
|
}
|
|
8384
9265
|
/**
|
|
8385
9266
|
* One best-effort delivery attempt for an event ALREADY in the ledger. POSTs the
|
|
@@ -8429,7 +9310,7 @@ var BillingPublisher = class {
|
|
|
8429
9310
|
try {
|
|
8430
9311
|
this.ensureDir();
|
|
8431
9312
|
const file = (0, import_node_path14.join)(this.billingDir, deliveredFileName(event.ts));
|
|
8432
|
-
(0,
|
|
9313
|
+
(0, import_node_fs21.appendFileSync)(file, JSON.stringify({ id: event.id, deliveredAt: this.now() }) + "\n", "utf8");
|
|
8433
9314
|
} catch (error) {
|
|
8434
9315
|
this.logger.warn("[BillingPublisher] failed to append delivery marker", {
|
|
8435
9316
|
error: error instanceof Error ? error.message : String(error)
|
|
@@ -8438,20 +9319,20 @@ var BillingPublisher = class {
|
|
|
8438
9319
|
}
|
|
8439
9320
|
ensureDir() {
|
|
8440
9321
|
if (this.dirEnsured) return;
|
|
8441
|
-
(0,
|
|
9322
|
+
(0, import_node_fs21.mkdirSync)(this.billingDir, { recursive: true });
|
|
8442
9323
|
this.dirEnsured = true;
|
|
8443
9324
|
}
|
|
8444
9325
|
};
|
|
8445
9326
|
|
|
8446
9327
|
// src/billing/billingReader.ts
|
|
8447
|
-
var
|
|
9328
|
+
var import_node_fs22 = require("fs");
|
|
8448
9329
|
var import_node_path15 = require("path");
|
|
8449
9330
|
function readBillingLedger(billingDir) {
|
|
8450
9331
|
const view = { events: [], deliveredIds: /* @__PURE__ */ new Set() };
|
|
8451
|
-
if (!(0,
|
|
9332
|
+
if (!(0, import_node_fs22.existsSync)(billingDir)) return view;
|
|
8452
9333
|
let files;
|
|
8453
9334
|
try {
|
|
8454
|
-
files = (0,
|
|
9335
|
+
files = (0, import_node_fs22.readdirSync)(billingDir);
|
|
8455
9336
|
} catch {
|
|
8456
9337
|
return view;
|
|
8457
9338
|
}
|
|
@@ -8482,7 +9363,7 @@ function readBillingStatus(billingDir) {
|
|
|
8482
9363
|
function parseLines(dir, file) {
|
|
8483
9364
|
let raw;
|
|
8484
9365
|
try {
|
|
8485
|
-
raw = (0,
|
|
9366
|
+
raw = (0, import_node_fs22.readFileSync)((0, import_node_path15.join)(dir, file), "utf8");
|
|
8486
9367
|
} catch {
|
|
8487
9368
|
return [];
|
|
8488
9369
|
}
|
|
@@ -8668,6 +9549,76 @@ var TokenRefreshScheduler = class {
|
|
|
8668
9549
|
}
|
|
8669
9550
|
};
|
|
8670
9551
|
|
|
9552
|
+
// src/routeLeaseSubscriptionPreflight.ts
|
|
9553
|
+
var import_provider_proxy3 = require("@omnicross/core/provider-proxy");
|
|
9554
|
+
var import_AccountAllowanceScheduling4 = require("@omnicross/core/pipeline/AccountAllowanceScheduling");
|
|
9555
|
+
var import_SubscriptionAccountHealth3 = require("@omnicross/core/pipeline/SubscriptionAccountHealth");
|
|
9556
|
+
var import_accountModelMap = require("@omnicross/subscriptions/scheduler/accountModelMap");
|
|
9557
|
+
var PROVIDERS = /* @__PURE__ */ new Set(["claude", "codex", "gemini", "opencodego"]);
|
|
9558
|
+
function accountArray(config, providerId) {
|
|
9559
|
+
const record = config;
|
|
9560
|
+
const key = `${providerId}Accounts`;
|
|
9561
|
+
const accounts = record[key];
|
|
9562
|
+
if (Array.isArray(accounts)) return accounts;
|
|
9563
|
+
const legacy = record[providerId];
|
|
9564
|
+
if (!legacy || typeof legacy !== "object") return [];
|
|
9565
|
+
const activeKey = `active${providerId[0].toUpperCase()}${providerId.slice(1)}AccountId`;
|
|
9566
|
+
return [{ id: String(record[activeKey] ?? "active"), enabled: true, tokens: legacy }];
|
|
9567
|
+
}
|
|
9568
|
+
function hasCredential(providerId, account) {
|
|
9569
|
+
const tokens = account.tokens;
|
|
9570
|
+
if (providerId === "opencodego") return typeof tokens.apiKey === "string" && tokens.apiKey.length > 0;
|
|
9571
|
+
return typeof tokens.accessToken === "string" && tokens.accessToken.length > 0;
|
|
9572
|
+
}
|
|
9573
|
+
function safeProviderId(value) {
|
|
9574
|
+
if (!PROVIDERS.has(value)) {
|
|
9575
|
+
throw new import_provider_proxy3.RouteLeaseError("upstream_not_found", "subscription provider was not found");
|
|
9576
|
+
}
|
|
9577
|
+
return value;
|
|
9578
|
+
}
|
|
9579
|
+
function createRouteLeaseSubscriptionPreflight(credentials) {
|
|
9580
|
+
return {
|
|
9581
|
+
async assertAvailable(upstream, model) {
|
|
9582
|
+
const providerId = safeProviderId(upstream.providerId);
|
|
9583
|
+
const config = await credentials.getFullConfig();
|
|
9584
|
+
const all = accountArray(config, providerId);
|
|
9585
|
+
if (all.length === 0) {
|
|
9586
|
+
throw new import_provider_proxy3.RouteLeaseError("upstream_unavailable", "subscription provider has no configured account");
|
|
9587
|
+
}
|
|
9588
|
+
let bounded = all;
|
|
9589
|
+
if (upstream.kind === "account") {
|
|
9590
|
+
bounded = all.filter((account) => account.id === upstream.accountId);
|
|
9591
|
+
} else if (upstream.kind === "account-group") {
|
|
9592
|
+
bounded = all.filter((account) => account.group?.trim() === upstream.group);
|
|
9593
|
+
}
|
|
9594
|
+
if (bounded.length === 0) {
|
|
9595
|
+
throw new import_provider_proxy3.RouteLeaseError("upstream_not_found", "the selected subscription resource was not found");
|
|
9596
|
+
}
|
|
9597
|
+
const modelEligible = bounded.filter(
|
|
9598
|
+
(account) => (0, import_accountModelMap.accountSupportsModel)(account.supportedModels, model)
|
|
9599
|
+
);
|
|
9600
|
+
if (modelEligible.length === 0) {
|
|
9601
|
+
throw new import_provider_proxy3.RouteLeaseError("model_not_configured", "model is not supported by the selected subscription resource");
|
|
9602
|
+
}
|
|
9603
|
+
const credentialEligible = modelEligible.filter(
|
|
9604
|
+
(account) => account.enabled !== false && hasCredential(providerId, account)
|
|
9605
|
+
);
|
|
9606
|
+
const health2 = (0, import_SubscriptionAccountHealth3.getSharedAccountHealth)();
|
|
9607
|
+
const allowance = (0, import_AccountAllowanceScheduling4.getSharedAccountAllowanceScheduling)();
|
|
9608
|
+
const candidates = credentialEligible.filter(
|
|
9609
|
+
(account) => health2.isSchedulable(providerId, account.id) && allowance.preview(providerId, account.id, account.priority ?? 50).schedulable
|
|
9610
|
+
);
|
|
9611
|
+
if (candidates.length > 0) return;
|
|
9612
|
+
if (upstream.kind === "account") {
|
|
9613
|
+
throw new import_provider_proxy3.RouteLeaseError("upstream_unavailable", "the selected subscription account is unavailable");
|
|
9614
|
+
}
|
|
9615
|
+
throw new import_provider_proxy3.RouteLeaseError("upstream_exhausted", "the selected subscription pool has no eligible account", {
|
|
9616
|
+
retryAfterSeconds: 30
|
|
9617
|
+
});
|
|
9618
|
+
}
|
|
9619
|
+
};
|
|
9620
|
+
}
|
|
9621
|
+
|
|
8671
9622
|
// src/webhook/WebhookDispatcher.ts
|
|
8672
9623
|
var import_node_crypto14 = require("crypto");
|
|
8673
9624
|
var import_upstreamFetch7 = require("@omnicross/core/pipeline/upstreamFetch");
|
|
@@ -8850,11 +9801,11 @@ function buildDaemon(config, paths) {
|
|
|
8850
9801
|
new JsonAccountAllowancePersistence(defaultAccountAllowancePath(paths.configPath))
|
|
8851
9802
|
);
|
|
8852
9803
|
(0, import_AccountAllowanceStore4.setSharedAccountAllowanceStore)(accountAllowanceStore);
|
|
8853
|
-
(0,
|
|
9804
|
+
(0, import_AccountAllowanceScheduling5.getSharedAccountAllowanceScheduling)().configure(
|
|
8854
9805
|
(0, import_outbound_api4.normalizeServerConfig)(decryptedConfig.server).allowanceScheduling
|
|
8855
9806
|
);
|
|
8856
9807
|
const llmConfig = new ConfigFileProviderConfigSource(decryptedConfig);
|
|
8857
|
-
const keyDb = new JsonOutboundKeyDb(paths.keysPath);
|
|
9808
|
+
const keyDb = new JsonOutboundKeyDb(paths.keysPath, secretBox3);
|
|
8858
9809
|
const voucherDb = new JsonVoucherDb(defaultVouchersPath(paths.configPath));
|
|
8859
9810
|
const settingsStore = new JsonApiServerSettingsStore(paths.configPath, secretBox3);
|
|
8860
9811
|
const integrationStateStore = new IntegrationStateStore(
|
|
@@ -8917,11 +9868,22 @@ function buildDaemon(config, paths) {
|
|
|
8917
9868
|
const usageRecorder = new import_usage.UsageRecorder(usageEventStore, pricingEngine, logger, {
|
|
8918
9869
|
onRecord: (apiKeyId, costUsd, at) => keySpendTracker.add(apiKeyId, costUsd, at)
|
|
8919
9870
|
});
|
|
8920
|
-
const providerProxy = (0,
|
|
9871
|
+
const providerProxy = (0, import_provider_proxy4.getProviderProxy)({ llmConfig, apiKeyPool, usageRecorder });
|
|
9872
|
+
const routeLeaseManager = new import_provider_proxy4.RouteLeaseManager(
|
|
9873
|
+
providerProxy,
|
|
9874
|
+
new import_provider_proxy4.RouteLeaseTargetResolver(llmConfig, {
|
|
9875
|
+
providerKeys: apiKeyPool,
|
|
9876
|
+
subscriptions: createRouteLeaseSubscriptionPreflight(credentialStore)
|
|
9877
|
+
}),
|
|
9878
|
+
import_cli_launcher2.routeLeaseDescriptorPort,
|
|
9879
|
+
{ logger }
|
|
9880
|
+
);
|
|
9881
|
+
providerProxy.registerBeforeStop(() => routeLeaseManager.shutdown());
|
|
9882
|
+
providerProxy.registerBeforeStop(() => resetCliSessions());
|
|
8921
9883
|
llmConfig.setReloadHook(() => apiKeyPool.invalidateCache());
|
|
8922
9884
|
const accountHealthProbeScheduler = new AccountHealthProbeScheduler(
|
|
8923
9885
|
credentialStore,
|
|
8924
|
-
(0,
|
|
9886
|
+
(0, import_SubscriptionAccountHealth4.getSharedAccountHealth)(),
|
|
8925
9887
|
logger,
|
|
8926
9888
|
import_outbound_api4.DEFAULT_ACCOUNT_PROBE
|
|
8927
9889
|
);
|
|
@@ -8955,7 +9917,7 @@ function buildDaemon(config, paths) {
|
|
|
8955
9917
|
// lines through the injected logger (honors level/format/file sink).
|
|
8956
9918
|
logger
|
|
8957
9919
|
});
|
|
8958
|
-
const
|
|
9920
|
+
const auditDir = defaultAuditDir(paths.configPath);
|
|
8959
9921
|
const billingDir = defaultBillingDir(paths.configPath);
|
|
8960
9922
|
const adminServer = new AdminServer({
|
|
8961
9923
|
configPath: paths.configPath,
|
|
@@ -8968,6 +9930,7 @@ function buildDaemon(config, paths) {
|
|
|
8968
9930
|
keySpendReader: keySpendTracker,
|
|
8969
9931
|
settingsStore,
|
|
8970
9932
|
outboundApiServer,
|
|
9933
|
+
routeLeaseManager,
|
|
8971
9934
|
subscriptionAccounts,
|
|
8972
9935
|
accountAllowanceService,
|
|
8973
9936
|
allowanceRefreshScheduler: claudeAllowanceRefreshScheduler,
|
|
@@ -8989,10 +9952,16 @@ function buildDaemon(config, paths) {
|
|
|
8989
9952
|
// (NOT widening the least-authority writer — no token-returning read reachable).
|
|
8990
9953
|
oauthSessions: new OAuthSessionStore(),
|
|
8991
9954
|
// Real global fetch by default; a test seam (`paths.oauthExchangeFetch`) can
|
|
8992
|
-
// inject a mock so no real token endpoint is hit
|
|
8993
|
-
//
|
|
8994
|
-
//
|
|
8995
|
-
|
|
9955
|
+
// inject a mock so no real token endpoint is hit (one FetchLike for every
|
|
9956
|
+
// provider — the ctx below only matters on the real egress path).
|
|
9957
|
+
//
|
|
9958
|
+
// upstream-proxy: a PER-PROVIDER factory, so the exchange carries the same
|
|
9959
|
+
// `{ providerId }` ctx the CLI login and the token refresh already pass.
|
|
9960
|
+
// Without it the interactive login resolved only the global/env proxy layers
|
|
9961
|
+
// — `server.proxy.byProvider[...]` was silently skipped — and the call was
|
|
9962
|
+
// excluded from the upstream trace, so a failing login left no evidence.
|
|
9963
|
+
// `redactBodies` keeps the code/verifier + minted token out of that trace.
|
|
9964
|
+
oauthExchangeFetch: paths.oauthExchangeFetch ? () => paths.oauthExchangeFetch : (providerId) => (url, init) => (0, import_upstreamFetch8.fetchUpstream)(url, init, { providerId, redactBodies: true }),
|
|
8996
9965
|
subscriptionAccountAppender: credentialStore,
|
|
8997
9966
|
// Codex interactive OAuth (app-parity-2 child 5) — the async loopback flow store
|
|
8998
9967
|
// + the one-shot 127.0.0.1:1455 listener. Token captured + persisted daemon-side;
|
|
@@ -9044,7 +10013,8 @@ function buildDaemon(config, paths) {
|
|
|
9044
10013
|
// date-rotated audit store. Bound to the store dir here so the AdminServer
|
|
9045
10014
|
// carries no path/store coupling. Records hold IP/UA/bodies → admin-only,
|
|
9046
10015
|
// NEVER unauth, NEVER on `/health`. Routed in `AdminServer` (not `adminApi.ts`).
|
|
9047
|
-
auditReader: (query2) => readAuditRecords(
|
|
10016
|
+
auditReader: (query2) => readAuditRecords(auditDir, query2),
|
|
10017
|
+
auditStatsReader: (query2) => readAuditStats(auditDir, query2),
|
|
9048
10018
|
// billing-event-stream: the AUTHED `GET /admin/api/billing-status` returns the
|
|
9049
10019
|
// secret-free total/delivered/pending counts of the durable ledger.
|
|
9050
10020
|
billingStatusReader: () => readBillingStatus(billingDir)
|
|
@@ -9053,10 +10023,10 @@ function buildDaemon(config, paths) {
|
|
|
9053
10023
|
logger,
|
|
9054
10024
|
fetchImpl: (url, init) => (0, import_upstreamFetch8.fetchUpstream)(url, init)
|
|
9055
10025
|
});
|
|
9056
|
-
setWebhookRuntime(webhookDispatcher, (0,
|
|
9057
|
-
const auditWriter = new AuditWriter(
|
|
9058
|
-
const auditPruneSweeper = new AuditPruneSweeper(
|
|
9059
|
-
setAuditRuntime(auditWriter, auditPruneSweeper
|
|
10026
|
+
setWebhookRuntime(webhookDispatcher, (0, import_SubscriptionAccountHealth4.getSharedAccountHealth)());
|
|
10027
|
+
const auditWriter = new AuditWriter(auditDir, logger);
|
|
10028
|
+
const auditPruneSweeper = new AuditPruneSweeper(auditDir, logger, import_audit_types.DEFAULT_AUDIT_CONFIG);
|
|
10029
|
+
setAuditRuntime(auditWriter, auditPruneSweeper);
|
|
9060
10030
|
const billingPublisher = new BillingPublisher(billingDir, logger);
|
|
9061
10031
|
const billingRetrySweeper = new BillingRetrySweeper(
|
|
9062
10032
|
billingDir,
|
|
@@ -9068,7 +10038,7 @@ function buildDaemon(config, paths) {
|
|
|
9068
10038
|
const tokenRefreshScheduler = new TokenRefreshScheduler(credentialStore, logger);
|
|
9069
10039
|
const accountHealthSweeper = new AccountHealthSweeper(
|
|
9070
10040
|
credentialStore,
|
|
9071
|
-
(0,
|
|
10041
|
+
(0, import_SubscriptionAccountHealth4.getSharedAccountHealth)(),
|
|
9072
10042
|
logger
|
|
9073
10043
|
);
|
|
9074
10044
|
return {
|
|
@@ -9077,6 +10047,7 @@ function buildDaemon(config, paths) {
|
|
|
9077
10047
|
keyDb,
|
|
9078
10048
|
settingsStore,
|
|
9079
10049
|
providerProxy,
|
|
10050
|
+
routeLeaseManager,
|
|
9080
10051
|
outboundApiServer,
|
|
9081
10052
|
apiKeyPool,
|
|
9082
10053
|
autoDisableStore,
|
|
@@ -9101,7 +10072,7 @@ function buildDaemon(config, paths) {
|
|
|
9101
10072
|
};
|
|
9102
10073
|
}
|
|
9103
10074
|
function resetDaemonSingletonsForTests() {
|
|
9104
|
-
(0,
|
|
10075
|
+
(0, import_provider_proxy4.__resetProviderProxyForTests)();
|
|
9105
10076
|
(0, import_outbound_api4.__resetOutboundApiServerForTests)();
|
|
9106
10077
|
(0, import_subscriptionRegistryPort.setSubscriptionRegistryForOutbound)(null);
|
|
9107
10078
|
(0, import_subscriptions4.setSubscriptionProviderRegistry)(null);
|
|
@@ -9116,12 +10087,12 @@ function resetDaemonSingletonsForTests() {
|
|
|
9116
10087
|
resetBillingRuntimeForTests();
|
|
9117
10088
|
(0, import_SubscriptionIdentityStore3.__resetSharedIdentityStoreForTests)();
|
|
9118
10089
|
(0, import_AccountAllowanceStore4.__resetSharedAccountAllowanceStoreForTests)();
|
|
9119
|
-
(0,
|
|
10090
|
+
(0, import_AccountAllowanceScheduling5.__resetSharedAccountAllowanceSchedulingForTests)();
|
|
9120
10091
|
}
|
|
9121
10092
|
function isTokensStoreReadable(tokensPath) {
|
|
9122
10093
|
try {
|
|
9123
|
-
if (!(0,
|
|
9124
|
-
(0,
|
|
10094
|
+
if (!(0, import_node_fs23.existsSync)(tokensPath)) return true;
|
|
10095
|
+
(0, import_node_fs23.accessSync)(tokensPath, import_node_fs23.constants.R_OK);
|
|
9125
10096
|
return true;
|
|
9126
10097
|
} catch {
|
|
9127
10098
|
return false;
|