codex-multi-auth 2.0.2 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +91 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/account-policy.d.ts +22 -0
- package/dist/lib/account-policy.d.ts.map +1 -0
- package/dist/lib/account-policy.js +159 -0
- package/dist/lib/account-policy.js.map +1 -0
- package/dist/lib/accounts.d.ts.map +1 -1
- package/dist/lib/accounts.js +2 -1
- package/dist/lib/accounts.js.map +1 -1
- package/dist/lib/budget-guard.d.ts +39 -0
- package/dist/lib/budget-guard.d.ts.map +1 -0
- package/dist/lib/budget-guard.js +201 -0
- package/dist/lib/budget-guard.js.map +1 -0
- package/dist/lib/codex-manager/commands/account.d.ts +13 -0
- package/dist/lib/codex-manager/commands/account.d.ts.map +1 -0
- package/dist/lib/codex-manager/commands/account.js +156 -0
- package/dist/lib/codex-manager/commands/account.js.map +1 -0
- package/dist/lib/codex-manager/commands/bridge.d.ts +6 -0
- package/dist/lib/codex-manager/commands/bridge.d.ts.map +1 -0
- package/dist/lib/codex-manager/commands/bridge.js +167 -0
- package/dist/lib/codex-manager/commands/bridge.js.map +1 -0
- package/dist/lib/codex-manager/commands/budget.d.ts +12 -0
- package/dist/lib/codex-manager/commands/budget.d.ts.map +1 -0
- package/dist/lib/codex-manager/commands/budget.js +123 -0
- package/dist/lib/codex-manager/commands/budget.js.map +1 -0
- package/dist/lib/codex-manager/commands/integrations.d.ts +6 -0
- package/dist/lib/codex-manager/commands/integrations.d.ts.map +1 -0
- package/dist/lib/codex-manager/commands/integrations.js +78 -0
- package/dist/lib/codex-manager/commands/integrations.js.map +1 -0
- package/dist/lib/codex-manager/commands/models.d.ts +14 -0
- package/dist/lib/codex-manager/commands/models.d.ts.map +1 -0
- package/dist/lib/codex-manager/commands/models.js +74 -0
- package/dist/lib/codex-manager/commands/models.js.map +1 -0
- package/dist/lib/codex-manager/commands/monitor.d.ts +22 -0
- package/dist/lib/codex-manager/commands/monitor.d.ts.map +1 -0
- package/dist/lib/codex-manager/commands/monitor.js +94 -0
- package/dist/lib/codex-manager/commands/monitor.js.map +1 -0
- package/dist/lib/codex-manager/commands/rotation.d.ts +1 -0
- package/dist/lib/codex-manager/commands/rotation.d.ts.map +1 -1
- package/dist/lib/codex-manager/commands/rotation.js +293 -10
- package/dist/lib/codex-manager/commands/rotation.js.map +1 -1
- package/dist/lib/codex-manager/commands/usage.d.ts +13 -0
- package/dist/lib/codex-manager/commands/usage.d.ts.map +1 -0
- package/dist/lib/codex-manager/commands/usage.js +347 -0
- package/dist/lib/codex-manager/commands/usage.js.map +1 -0
- package/dist/lib/codex-manager/help.d.ts.map +1 -1
- package/dist/lib/codex-manager/help.js +8 -0
- package/dist/lib/codex-manager/help.js.map +1 -1
- package/dist/lib/codex-manager.d.ts.map +1 -1
- package/dist/lib/codex-manager.js +42 -2
- package/dist/lib/codex-manager.js.map +1 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +2 -22
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/constants.d.ts +1 -0
- package/dist/lib/constants.d.ts.map +1 -1
- package/dist/lib/constants.js +1 -0
- package/dist/lib/constants.js.map +1 -1
- package/dist/lib/env-parsing.d.ts +21 -0
- package/dist/lib/env-parsing.d.ts.map +1 -0
- package/dist/lib/env-parsing.js +34 -0
- package/dist/lib/env-parsing.js.map +1 -0
- package/dist/lib/index.d.ts +9 -0
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +9 -0
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/integration-generators.d.ts +14 -0
- package/dist/lib/integration-generators.d.ts.map +1 -0
- package/dist/lib/integration-generators.js +93 -0
- package/dist/lib/integration-generators.js.map +1 -0
- package/dist/lib/local-bridge.d.ts +17 -0
- package/dist/lib/local-bridge.d.ts.map +1 -0
- package/dist/lib/local-bridge.js +249 -0
- package/dist/lib/local-bridge.js.map +1 -0
- package/dist/lib/local-client-tokens.d.ts +37 -0
- package/dist/lib/local-client-tokens.d.ts.map +1 -0
- package/dist/lib/local-client-tokens.js +200 -0
- package/dist/lib/local-client-tokens.js.map +1 -0
- package/dist/lib/model-capability-matrix.d.ts +38 -0
- package/dist/lib/model-capability-matrix.d.ts.map +1 -0
- package/dist/lib/model-capability-matrix.js +89 -0
- package/dist/lib/model-capability-matrix.js.map +1 -0
- package/dist/lib/policy/runtime-policy.d.ts +59 -0
- package/dist/lib/policy/runtime-policy.d.ts.map +1 -0
- package/dist/lib/policy/runtime-policy.js +156 -0
- package/dist/lib/policy/runtime-policy.js.map +1 -0
- package/dist/lib/proactive-refresh.js +4 -4
- package/dist/lib/proactive-refresh.js.map +1 -1
- package/dist/lib/refresh-lease.d.ts.map +1 -1
- package/dist/lib/refresh-lease.js +1 -10
- package/dist/lib/refresh-lease.js.map +1 -1
- package/dist/lib/routing-profiles.d.ts +36 -0
- package/dist/lib/routing-profiles.d.ts.map +1 -0
- package/dist/lib/routing-profiles.js +203 -0
- package/dist/lib/routing-profiles.js.map +1 -0
- package/dist/lib/runtime-rotation-proxy.d.ts.map +1 -1
- package/dist/lib/runtime-rotation-proxy.js +96 -6
- package/dist/lib/runtime-rotation-proxy.js.map +1 -1
- package/dist/lib/usage/index.d.ts +5 -0
- package/dist/lib/usage/index.d.ts.map +1 -0
- package/dist/lib/usage/index.js +5 -0
- package/dist/lib/usage/index.js.map +1 -0
- package/dist/lib/usage/ledger.d.ts +12 -0
- package/dist/lib/usage/ledger.d.ts.map +1 -0
- package/dist/lib/usage/ledger.js +493 -0
- package/dist/lib/usage/ledger.js.map +1 -0
- package/dist/lib/usage/pricing.d.ts +11 -0
- package/dist/lib/usage/pricing.d.ts.map +1 -0
- package/dist/lib/usage/pricing.js +67 -0
- package/dist/lib/usage/pricing.js.map +1 -0
- package/dist/lib/usage/redaction.d.ts +10 -0
- package/dist/lib/usage/redaction.d.ts.map +1 -0
- package/dist/lib/usage/redaction.js +129 -0
- package/dist/lib/usage/redaction.js.map +1 -0
- package/dist/lib/usage/types.d.ts +89 -0
- package/dist/lib/usage/types.d.ts.map +1 -0
- package/dist/lib/usage/types.js +2 -0
- package/dist/lib/usage/types.js.map +1 -0
- package/package.json +1 -1
- package/scripts/codex-routing.js +19 -12
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { createServer } from "node:http";
|
|
2
|
+
import { Hono } from "hono";
|
|
3
|
+
import { fetch as undiciFetch } from "undici";
|
|
4
|
+
import { verifyLocalClientBearerToken } from "./local-client-tokens.js";
|
|
5
|
+
import { appendUsageLedgerRow } from "./usage/index.js";
|
|
6
|
+
const DEFAULT_HOST = "127.0.0.1";
|
|
7
|
+
const HOP_BY_HOP_HEADERS = new Set([
|
|
8
|
+
"connection",
|
|
9
|
+
"content-length",
|
|
10
|
+
"expect",
|
|
11
|
+
"keep-alive",
|
|
12
|
+
"proxy-authenticate",
|
|
13
|
+
"proxy-authorization",
|
|
14
|
+
"te",
|
|
15
|
+
"trailer",
|
|
16
|
+
"transfer-encoding",
|
|
17
|
+
"upgrade",
|
|
18
|
+
]);
|
|
19
|
+
const DECODED_UPSTREAM_RESPONSE_HEADERS = new Set(["content-encoding"]);
|
|
20
|
+
function isLoopbackHost(host) {
|
|
21
|
+
const normalized = host.trim().toLowerCase();
|
|
22
|
+
return normalized === "127.0.0.1" || normalized === "localhost" || normalized === "::1";
|
|
23
|
+
}
|
|
24
|
+
function responseHeadersForClient(headers) {
|
|
25
|
+
const result = new Headers();
|
|
26
|
+
for (const [key, value] of headers.entries()) {
|
|
27
|
+
if (HOP_BY_HOP_HEADERS.has(key.toLowerCase()))
|
|
28
|
+
continue;
|
|
29
|
+
if (DECODED_UPSTREAM_RESPONSE_HEADERS.has(key.toLowerCase()))
|
|
30
|
+
continue;
|
|
31
|
+
result.set(key, value);
|
|
32
|
+
}
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
function forwardHeaders(headers) {
|
|
36
|
+
const result = new Headers(headers);
|
|
37
|
+
for (const key of HOP_BY_HOP_HEADERS) {
|
|
38
|
+
result.delete(key);
|
|
39
|
+
}
|
|
40
|
+
result.delete("host");
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
async function streamToArrayBuffer(stream) {
|
|
44
|
+
if (!stream)
|
|
45
|
+
return null;
|
|
46
|
+
const response = new Response(stream);
|
|
47
|
+
return response.arrayBuffer();
|
|
48
|
+
}
|
|
49
|
+
async function closeServer(server, sockets) {
|
|
50
|
+
if (!server.listening)
|
|
51
|
+
return;
|
|
52
|
+
const closed = new Promise((resolve, reject) => {
|
|
53
|
+
server.close((error) => {
|
|
54
|
+
if (error) {
|
|
55
|
+
reject(error);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
resolve();
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
server.closeIdleConnections?.();
|
|
62
|
+
for (const socket of sockets) {
|
|
63
|
+
socket.destroy();
|
|
64
|
+
}
|
|
65
|
+
await closed;
|
|
66
|
+
}
|
|
67
|
+
async function toWebRequest(req, host, port) {
|
|
68
|
+
const url = new URL(req.url ?? "/", `http://${host}:${port}`);
|
|
69
|
+
const headers = new Headers();
|
|
70
|
+
for (const [key, value] of Object.entries(req.headers)) {
|
|
71
|
+
if (value === undefined)
|
|
72
|
+
continue;
|
|
73
|
+
if (Array.isArray(value)) {
|
|
74
|
+
for (const item of value)
|
|
75
|
+
headers.append(key, item);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
headers.set(key, value);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const method = req.method ?? "GET";
|
|
82
|
+
const body = method === "GET" || method === "HEAD"
|
|
83
|
+
? undefined
|
|
84
|
+
: await new Response(req).arrayBuffer();
|
|
85
|
+
return new Request(url, { method, headers, body });
|
|
86
|
+
}
|
|
87
|
+
function writeWebResponse(res, response) {
|
|
88
|
+
res.writeHead(response.status, Object.fromEntries(response.headers.entries()));
|
|
89
|
+
if (!response.body) {
|
|
90
|
+
res.end();
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const reader = response.body.getReader();
|
|
94
|
+
const pump = async () => {
|
|
95
|
+
while (true) {
|
|
96
|
+
const { done, value } = await reader.read();
|
|
97
|
+
if (done)
|
|
98
|
+
break;
|
|
99
|
+
if (value)
|
|
100
|
+
res.write(Buffer.from(value));
|
|
101
|
+
}
|
|
102
|
+
res.end();
|
|
103
|
+
};
|
|
104
|
+
void pump().catch((error) => {
|
|
105
|
+
if (!res.destroyed) {
|
|
106
|
+
res.destroy(error instanceof Error ? error : undefined);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
export async function startLocalBridge(options) {
|
|
111
|
+
const host = options.host ?? DEFAULT_HOST;
|
|
112
|
+
if (!isLoopbackHost(host)) {
|
|
113
|
+
throw new Error("Local bridge only supports loopback hosts.");
|
|
114
|
+
}
|
|
115
|
+
const runtimeBaseUrl = options.runtimeBaseUrl.trim().replace(/\/+$/, "");
|
|
116
|
+
if (!runtimeBaseUrl) {
|
|
117
|
+
throw new Error("Local bridge requires a runtimeBaseUrl.");
|
|
118
|
+
}
|
|
119
|
+
const port = options.port ?? 0;
|
|
120
|
+
const fetchImpl = options.fetchImpl ?? undiciFetch;
|
|
121
|
+
const requireAuth = options.requireAuth ?? true;
|
|
122
|
+
const verifyBearerToken = options.verifyBearerToken ?? verifyLocalClientBearerToken;
|
|
123
|
+
const app = new Hono();
|
|
124
|
+
app.get("/health", (context) => context.json({
|
|
125
|
+
ok: true,
|
|
126
|
+
service: "codex-multi-auth-local-bridge",
|
|
127
|
+
runtimeBaseUrl,
|
|
128
|
+
}));
|
|
129
|
+
const forward = async (request, targetPath) => {
|
|
130
|
+
const startedAt = Date.now();
|
|
131
|
+
if (requireAuth) {
|
|
132
|
+
const token = await verifyBearerToken(request.headers.get("authorization"), startedAt);
|
|
133
|
+
if (!token) {
|
|
134
|
+
return new Response(JSON.stringify({
|
|
135
|
+
error: {
|
|
136
|
+
message: "Local bridge rejected an unauthenticated request.",
|
|
137
|
+
code: "local_bridge_unauthorized",
|
|
138
|
+
},
|
|
139
|
+
}), {
|
|
140
|
+
status: 401,
|
|
141
|
+
headers: { "content-type": "application/json; charset=utf-8" },
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
const targetUrl = `${runtimeBaseUrl}${targetPath}`;
|
|
146
|
+
let upstream;
|
|
147
|
+
try {
|
|
148
|
+
upstream = await fetchImpl(targetUrl, {
|
|
149
|
+
method: request.method,
|
|
150
|
+
headers: forwardHeaders(request.headers),
|
|
151
|
+
body: request.method === "GET" || request.method === "HEAD"
|
|
152
|
+
? undefined
|
|
153
|
+
: await streamToArrayBuffer(request.body),
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
await appendUsageLedgerRow({
|
|
158
|
+
source: "local-bridge",
|
|
159
|
+
operation: targetPath === "/v1/models" ? "models" : "responses",
|
|
160
|
+
outcome: "failure",
|
|
161
|
+
statusCode: 502,
|
|
162
|
+
errorCode: "local_bridge_upstream_error",
|
|
163
|
+
durationMs: Date.now() - startedAt,
|
|
164
|
+
}).catch(() => undefined);
|
|
165
|
+
return new Response(JSON.stringify({
|
|
166
|
+
error: {
|
|
167
|
+
message: "Local bridge failed to reach the runtime proxy.",
|
|
168
|
+
code: "local_bridge_upstream_error",
|
|
169
|
+
},
|
|
170
|
+
}), {
|
|
171
|
+
status: 502,
|
|
172
|
+
headers: { "content-type": "application/json; charset=utf-8" },
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
await appendUsageLedgerRow({
|
|
176
|
+
source: "local-bridge",
|
|
177
|
+
operation: targetPath === "/v1/models" ? "models" : "responses",
|
|
178
|
+
outcome: upstream.ok ? "success" : "failure",
|
|
179
|
+
statusCode: upstream.status,
|
|
180
|
+
durationMs: Date.now() - startedAt,
|
|
181
|
+
}).catch(() => undefined);
|
|
182
|
+
return new Response(upstream.body, {
|
|
183
|
+
status: upstream.status,
|
|
184
|
+
statusText: upstream.statusText,
|
|
185
|
+
headers: responseHeadersForClient(upstream.headers),
|
|
186
|
+
});
|
|
187
|
+
};
|
|
188
|
+
app.get("/v1/models", (context) => forward(context.req.raw, "/v1/models"));
|
|
189
|
+
app.post("/v1/responses", (context) => forward(context.req.raw, "/v1/responses"));
|
|
190
|
+
app.all("*", (context) => context.json({
|
|
191
|
+
error: {
|
|
192
|
+
message: "Local bridge only accepts /health, /v1/models, and /v1/responses.",
|
|
193
|
+
code: "local_bridge_not_found",
|
|
194
|
+
},
|
|
195
|
+
}, 404));
|
|
196
|
+
const server = createServer((req, res) => {
|
|
197
|
+
void (async () => {
|
|
198
|
+
try {
|
|
199
|
+
const webRequest = await toWebRequest(req, host, resolvedPort);
|
|
200
|
+
writeWebResponse(res, await app.fetch(webRequest));
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
if (!res.headersSent) {
|
|
204
|
+
res.writeHead(500, { "content-type": "application/json; charset=utf-8" });
|
|
205
|
+
res.end(`${JSON.stringify({
|
|
206
|
+
error: {
|
|
207
|
+
message: "Local bridge failed before forwarding the request.",
|
|
208
|
+
code: "local_bridge_error",
|
|
209
|
+
},
|
|
210
|
+
})}\n`);
|
|
211
|
+
}
|
|
212
|
+
else if (!res.destroyed) {
|
|
213
|
+
res.destroy(error instanceof Error ? error : undefined);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
})();
|
|
217
|
+
});
|
|
218
|
+
const sockets = new Set();
|
|
219
|
+
server.on("connection", (socket) => {
|
|
220
|
+
sockets.add(socket);
|
|
221
|
+
socket.once("close", () => sockets.delete(socket));
|
|
222
|
+
});
|
|
223
|
+
let resolvedPort = port;
|
|
224
|
+
await new Promise((resolve, reject) => {
|
|
225
|
+
const onError = (error) => {
|
|
226
|
+
server.off("listening", onListening);
|
|
227
|
+
reject(error);
|
|
228
|
+
};
|
|
229
|
+
const onListening = () => {
|
|
230
|
+
server.off("error", onError);
|
|
231
|
+
const address = server.address();
|
|
232
|
+
resolvedPort =
|
|
233
|
+
typeof address === "object" && address ? address.port : port;
|
|
234
|
+
resolve();
|
|
235
|
+
};
|
|
236
|
+
server.once("error", onError);
|
|
237
|
+
server.once("listening", onListening);
|
|
238
|
+
server.listen(port, host);
|
|
239
|
+
});
|
|
240
|
+
return {
|
|
241
|
+
host,
|
|
242
|
+
port: resolvedPort,
|
|
243
|
+
baseUrl: `http://${host}:${resolvedPort}`,
|
|
244
|
+
close: async () => {
|
|
245
|
+
await closeServer(server, sockets);
|
|
246
|
+
},
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=local-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-bridge.js","sourceRoot":"","sources":["../../lib/local-bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export interface LocalClientTokenRecord {
|
|
2
|
+
id: string;
|
|
3
|
+
label: string;
|
|
4
|
+
prefix: string;
|
|
5
|
+
tokenHash: string;
|
|
6
|
+
createdAt: number;
|
|
7
|
+
lastUsedAt: number | null;
|
|
8
|
+
revokedAt: number | null;
|
|
9
|
+
}
|
|
10
|
+
export interface LocalClientTokenStore {
|
|
11
|
+
version: 1;
|
|
12
|
+
tokens: LocalClientTokenRecord[];
|
|
13
|
+
}
|
|
14
|
+
export interface CreatedLocalClientToken {
|
|
15
|
+
plainToken: string;
|
|
16
|
+
record: LocalClientTokenRecord;
|
|
17
|
+
}
|
|
18
|
+
export declare function getLocalClientTokenPath(): string;
|
|
19
|
+
export declare function loadLocalClientTokenStore(): Promise<LocalClientTokenStore>;
|
|
20
|
+
export declare function saveLocalClientTokenStore(store: LocalClientTokenStore): Promise<void>;
|
|
21
|
+
export declare function createLocalClientTokenRecord(input?: {
|
|
22
|
+
label?: string;
|
|
23
|
+
now?: number;
|
|
24
|
+
}): CreatedLocalClientToken;
|
|
25
|
+
export declare function addLocalClientToken(input?: {
|
|
26
|
+
label?: string;
|
|
27
|
+
now?: number;
|
|
28
|
+
}): Promise<CreatedLocalClientToken>;
|
|
29
|
+
export declare function rotateLocalClientToken(input: {
|
|
30
|
+
id: string;
|
|
31
|
+
label?: string;
|
|
32
|
+
now?: number;
|
|
33
|
+
}): Promise<CreatedLocalClientToken | null>;
|
|
34
|
+
export declare function revokeLocalClientToken(id: string, now?: number): Promise<boolean>;
|
|
35
|
+
export declare function verifyLocalClientBearerToken(authorizationHeader: string | null, now?: number): Promise<LocalClientTokenRecord | null>;
|
|
36
|
+
export declare function resetLocalClientTokenWriteQueueForTests(): void;
|
|
37
|
+
//# sourceMappingURL=local-client-tokens.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-client-tokens.d.ts","sourceRoot":"","sources":["../../lib/local-client-tokens.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,sBAAsB;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,qBAAqB;IACrC,OAAO,EAAE,CAAC,CAAC;IACX,MAAM,EAAE,sBAAsB,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,uBAAuB;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,sBAAsB,CAAC;CAC/B;AA0FD,wBAAgB,uBAAuB,IAAI,MAAM,CAEhD;AAED,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,qBAAqB,CAAC,CAahF;AAED,wBAAsB,yBAAyB,CAC9C,KAAK,EAAE,qBAAqB,GAC1B,OAAO,CAAC,IAAI,CAAC,CAsCf;AAED,wBAAgB,4BAA4B,CAAC,KAAK,GAAE;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACR,GAAG,uBAAuB,CAY/B;AAED,wBAAsB,mBAAmB,CAAC,KAAK,GAAE;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACR,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAMxC;AAED,wBAAsB,sBAAsB,CAAC,KAAK,EAAE;IACnD,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACb,GAAG,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC,CAa1C;AAED,wBAAsB,sBAAsB,CAC3C,EAAE,EAAE,MAAM,EACV,GAAG,SAAa,GACd,OAAO,CAAC,OAAO,CAAC,CAOlB;AAED,wBAAsB,4BAA4B,CACjD,mBAAmB,EAAE,MAAM,GAAG,IAAI,EAClC,GAAG,SAAa,GACd,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAaxC;AAED,wBAAgB,uCAAuC,IAAI,IAAI,CAE9D"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
2
|
+
import { existsSync, promises as fs } from "node:fs";
|
|
3
|
+
import { basename, join } from "node:path";
|
|
4
|
+
import { logWarn } from "./logger.js";
|
|
5
|
+
import { getCodexMultiAuthDir } from "./runtime-paths.js";
|
|
6
|
+
import { isRecord, sleep } from "./utils.js";
|
|
7
|
+
const TOKEN_FILE_NAME = "local-client-tokens.json";
|
|
8
|
+
const TOKEN_PREFIX = "cma_local";
|
|
9
|
+
const RETRYABLE_FS_CODES = new Set(["EBUSY", "EPERM"]);
|
|
10
|
+
let writeQueue = Promise.resolve();
|
|
11
|
+
function isRetryableFsError(error) {
|
|
12
|
+
const code = error?.code;
|
|
13
|
+
return typeof code === "string" && RETRYABLE_FS_CODES.has(code);
|
|
14
|
+
}
|
|
15
|
+
function normalizeLabel(value) {
|
|
16
|
+
const trimmed = value?.trim();
|
|
17
|
+
return trimmed && trimmed.length > 0 ? trimmed.slice(0, 80) : "local-client";
|
|
18
|
+
}
|
|
19
|
+
function hashToken(token) {
|
|
20
|
+
return `sha256:${createHash("sha256").update(token).digest("hex")}`;
|
|
21
|
+
}
|
|
22
|
+
function createPlainToken() {
|
|
23
|
+
return `${TOKEN_PREFIX}_${randomBytes(32).toString("base64url")}`;
|
|
24
|
+
}
|
|
25
|
+
function tokenPrefix(token) {
|
|
26
|
+
return token.slice(0, 18);
|
|
27
|
+
}
|
|
28
|
+
function emptyStore() {
|
|
29
|
+
return { version: 1, tokens: [] };
|
|
30
|
+
}
|
|
31
|
+
function normalizeRecord(value) {
|
|
32
|
+
if (!isRecord(value))
|
|
33
|
+
return null;
|
|
34
|
+
if (typeof value.id !== "string" || value.id.trim().length === 0)
|
|
35
|
+
return null;
|
|
36
|
+
if (typeof value.tokenHash !== "string" ||
|
|
37
|
+
!value.tokenHash.startsWith("sha256:")) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
id: value.id.trim(),
|
|
42
|
+
label: normalizeLabel(typeof value.label === "string" ? value.label : undefined),
|
|
43
|
+
prefix: typeof value.prefix === "string" ? value.prefix.slice(0, 32) : "",
|
|
44
|
+
tokenHash: value.tokenHash,
|
|
45
|
+
createdAt: typeof value.createdAt === "number" && Number.isFinite(value.createdAt)
|
|
46
|
+
? value.createdAt
|
|
47
|
+
: 0,
|
|
48
|
+
lastUsedAt: typeof value.lastUsedAt === "number" && Number.isFinite(value.lastUsedAt)
|
|
49
|
+
? value.lastUsedAt
|
|
50
|
+
: null,
|
|
51
|
+
revokedAt: typeof value.revokedAt === "number" && Number.isFinite(value.revokedAt)
|
|
52
|
+
? value.revokedAt
|
|
53
|
+
: null,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function normalizeStore(value) {
|
|
57
|
+
if (!isRecord(value) || value.version !== 1 || !Array.isArray(value.tokens)) {
|
|
58
|
+
return emptyStore();
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
version: 1,
|
|
62
|
+
tokens: value.tokens
|
|
63
|
+
.map((entry) => normalizeRecord(entry))
|
|
64
|
+
.filter((entry) => entry !== null),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
async function readFileWithRetry(path) {
|
|
68
|
+
let lastError;
|
|
69
|
+
for (let attempt = 0; attempt < 5; attempt += 1) {
|
|
70
|
+
try {
|
|
71
|
+
return await fs.readFile(path, "utf8");
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
lastError = error;
|
|
75
|
+
if (!isRetryableFsError(error) || attempt >= 4)
|
|
76
|
+
throw error;
|
|
77
|
+
await sleep(10 * 2 ** attempt);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
throw lastError instanceof Error
|
|
81
|
+
? lastError
|
|
82
|
+
: new Error("local client token read retry exhausted");
|
|
83
|
+
}
|
|
84
|
+
export function getLocalClientTokenPath() {
|
|
85
|
+
return join(getCodexMultiAuthDir(), TOKEN_FILE_NAME);
|
|
86
|
+
}
|
|
87
|
+
export async function loadLocalClientTokenStore() {
|
|
88
|
+
const path = getLocalClientTokenPath();
|
|
89
|
+
if (!existsSync(path))
|
|
90
|
+
return emptyStore();
|
|
91
|
+
try {
|
|
92
|
+
return normalizeStore(JSON.parse(await readFileWithRetry(path)));
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
logWarn(`Failed to load local client tokens from ${basename(path)}: ${error instanceof Error ? error.message : String(error)}`);
|
|
96
|
+
return emptyStore();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
export async function saveLocalClientTokenStore(store) {
|
|
100
|
+
const path = getLocalClientTokenPath();
|
|
101
|
+
const payload = normalizeStore(store);
|
|
102
|
+
const task = async () => {
|
|
103
|
+
await fs.mkdir(getCodexMultiAuthDir(), { recursive: true, mode: 0o700 });
|
|
104
|
+
const tempPath = `${path}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`;
|
|
105
|
+
let moved = false;
|
|
106
|
+
try {
|
|
107
|
+
await fs.writeFile(tempPath, `${JSON.stringify(payload, null, 2)}\n`, {
|
|
108
|
+
encoding: "utf8",
|
|
109
|
+
mode: 0o600,
|
|
110
|
+
});
|
|
111
|
+
for (let attempt = 0; attempt < 5; attempt += 1) {
|
|
112
|
+
try {
|
|
113
|
+
await fs.rename(tempPath, path);
|
|
114
|
+
moved = true;
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
if (!isRetryableFsError(error) || attempt >= 4)
|
|
119
|
+
throw error;
|
|
120
|
+
await sleep(10 * 2 ** attempt);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
finally {
|
|
125
|
+
if (!moved) {
|
|
126
|
+
try {
|
|
127
|
+
await fs.unlink(tempPath);
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
// Best-effort temp cleanup.
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
const queued = writeQueue.catch(() => undefined).then(task);
|
|
136
|
+
writeQueue = queued.then(() => undefined, () => undefined);
|
|
137
|
+
await queued;
|
|
138
|
+
}
|
|
139
|
+
export function createLocalClientTokenRecord(input = {}) {
|
|
140
|
+
const plainToken = createPlainToken();
|
|
141
|
+
const record = {
|
|
142
|
+
id: randomUUID(),
|
|
143
|
+
label: normalizeLabel(input.label),
|
|
144
|
+
prefix: tokenPrefix(plainToken),
|
|
145
|
+
tokenHash: hashToken(plainToken),
|
|
146
|
+
createdAt: input.now ?? Date.now(),
|
|
147
|
+
lastUsedAt: null,
|
|
148
|
+
revokedAt: null,
|
|
149
|
+
};
|
|
150
|
+
return { plainToken, record };
|
|
151
|
+
}
|
|
152
|
+
export async function addLocalClientToken(input = {}) {
|
|
153
|
+
const store = await loadLocalClientTokenStore();
|
|
154
|
+
const created = createLocalClientTokenRecord(input);
|
|
155
|
+
store.tokens.push(created.record);
|
|
156
|
+
await saveLocalClientTokenStore(store);
|
|
157
|
+
return created;
|
|
158
|
+
}
|
|
159
|
+
export async function rotateLocalClientToken(input) {
|
|
160
|
+
const store = await loadLocalClientTokenStore();
|
|
161
|
+
const existing = store.tokens.find((record) => record.id === input.id);
|
|
162
|
+
if (!existing || existing.revokedAt !== null)
|
|
163
|
+
return null;
|
|
164
|
+
const now = input.now ?? Date.now();
|
|
165
|
+
existing.revokedAt = now;
|
|
166
|
+
const created = createLocalClientTokenRecord({
|
|
167
|
+
label: input.label ?? existing.label,
|
|
168
|
+
now,
|
|
169
|
+
});
|
|
170
|
+
store.tokens.push(created.record);
|
|
171
|
+
await saveLocalClientTokenStore(store);
|
|
172
|
+
return created;
|
|
173
|
+
}
|
|
174
|
+
export async function revokeLocalClientToken(id, now = Date.now()) {
|
|
175
|
+
const store = await loadLocalClientTokenStore();
|
|
176
|
+
const existing = store.tokens.find((record) => record.id === id);
|
|
177
|
+
if (!existing || existing.revokedAt !== null)
|
|
178
|
+
return false;
|
|
179
|
+
existing.revokedAt = now;
|
|
180
|
+
await saveLocalClientTokenStore(store);
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
export async function verifyLocalClientBearerToken(authorizationHeader, now = Date.now()) {
|
|
184
|
+
const match = authorizationHeader?.match(/^Bearer\s+(.+)$/i);
|
|
185
|
+
const token = match?.[1]?.trim();
|
|
186
|
+
if (!token)
|
|
187
|
+
return null;
|
|
188
|
+
const tokenHash = hashToken(token);
|
|
189
|
+
const store = await loadLocalClientTokenStore();
|
|
190
|
+
const record = store.tokens.find((entry) => entry.revokedAt === null && entry.tokenHash === tokenHash);
|
|
191
|
+
if (!record)
|
|
192
|
+
return null;
|
|
193
|
+
record.lastUsedAt = now;
|
|
194
|
+
await saveLocalClientTokenStore(store);
|
|
195
|
+
return record;
|
|
196
|
+
}
|
|
197
|
+
export function resetLocalClientTokenWriteQueueForTests() {
|
|
198
|
+
writeQueue = Promise.resolve();
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=local-client-tokens.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-client-tokens.js","sourceRoot":"","sources":["../../lib/local-client-tokens.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { AccountStorageV3 } from "./storage.js";
|
|
2
|
+
import { type ModelCapabilities, type ModelReasoningEffort, type PromptModelFamily } from "./request/helpers/model-map.js";
|
|
3
|
+
import { type EntitlementCacheSnapshot } from "./entitlement-cache.js";
|
|
4
|
+
import type { CapabilityPolicySnapshot, CapabilityPolicyStore } from "./capability-policy.js";
|
|
5
|
+
import type { QuotaCacheData, QuotaCacheEntry } from "./quota-cache.js";
|
|
6
|
+
export interface ModelCapabilityMatrixEntry {
|
|
7
|
+
accountIndex: number;
|
|
8
|
+
accountLabel: string;
|
|
9
|
+
accountKey: string;
|
|
10
|
+
model: string;
|
|
11
|
+
normalizedModel: string;
|
|
12
|
+
promptFamily: PromptModelFamily;
|
|
13
|
+
defaultReasoningEffort: ModelReasoningEffort;
|
|
14
|
+
supportedReasoningEfforts: readonly ModelReasoningEffort[];
|
|
15
|
+
capabilities: ModelCapabilities;
|
|
16
|
+
entitlementBlocked: boolean;
|
|
17
|
+
entitlementReason: string | null;
|
|
18
|
+
entitlementWaitMs: number;
|
|
19
|
+
capabilityPolicy: CapabilityPolicySnapshot | null;
|
|
20
|
+
capabilityBoost: number;
|
|
21
|
+
quota: QuotaCacheEntry | null;
|
|
22
|
+
available: boolean;
|
|
23
|
+
reasons: string[];
|
|
24
|
+
}
|
|
25
|
+
export interface ModelCapabilityMatrix {
|
|
26
|
+
generatedAt: number;
|
|
27
|
+
models: string[];
|
|
28
|
+
entries: ModelCapabilityMatrixEntry[];
|
|
29
|
+
}
|
|
30
|
+
export declare function buildModelCapabilityMatrix(input: {
|
|
31
|
+
storage: AccountStorageV3 | null;
|
|
32
|
+
models?: string[];
|
|
33
|
+
entitlements?: EntitlementCacheSnapshot | null;
|
|
34
|
+
capabilityPolicy?: CapabilityPolicyStore | null;
|
|
35
|
+
quotaCache?: QuotaCacheData | null;
|
|
36
|
+
now?: number;
|
|
37
|
+
}): ModelCapabilityMatrix;
|
|
38
|
+
//# sourceMappingURL=model-capability-matrix.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-capability-matrix.d.ts","sourceRoot":"","sources":["../../lib/model-capability-matrix.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAGN,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EACtB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAEN,KAAK,wBAAwB,EAC7B,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EACX,wBAAwB,EACxB,qBAAqB,EACrB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAGxE,MAAM,WAAW,0BAA0B;IAC1C,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,iBAAiB,CAAC;IAChC,sBAAsB,EAAE,oBAAoB,CAAC;IAC7C,yBAAyB,EAAE,SAAS,oBAAoB,EAAE,CAAC;IAC3D,YAAY,EAAE,iBAAiB,CAAC;IAChC,kBAAkB,EAAE,OAAO,CAAC;IAC5B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,wBAAwB,GAAG,IAAI,CAAC;IAClD,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,qBAAqB;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,0BAA0B,EAAE,CAAC;CACtC;AAsBD,wBAAgB,0BAA0B,CAAC,KAAK,EAAE;IACjD,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,YAAY,CAAC,EAAE,wBAAwB,GAAG,IAAI,CAAC;IAC/C,gBAAgB,CAAC,EAAE,qBAAqB,GAAG,IAAI,CAAC;IAChD,UAAU,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;IACnC,GAAG,CAAC,EAAE,MAAM,CAAC;CACb,GAAG,qBAAqB,CA8ExB"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { getAccountPolicyKey } from "./account-policy.js";
|
|
2
|
+
import { MODEL_PROFILES, resolveNormalizedModel, } from "./request/helpers/model-map.js";
|
|
3
|
+
import { resolveEntitlementAccountKey, } from "./entitlement-cache.js";
|
|
4
|
+
import { findQuotaCacheEntryForAccount } from "./quota-readiness.js";
|
|
5
|
+
function getEntitlementBlock(snapshot, accountKeys, normalizedModel, now) {
|
|
6
|
+
if (!snapshot)
|
|
7
|
+
return { blocked: false, waitMs: 0, reason: null };
|
|
8
|
+
for (const accountKey of accountKeys) {
|
|
9
|
+
const blocks = snapshot.accounts[accountKey] ?? [];
|
|
10
|
+
const block = blocks.find((entry) => entry.model === normalizedModel);
|
|
11
|
+
if (!block || block.blockedUntil <= now)
|
|
12
|
+
continue;
|
|
13
|
+
return {
|
|
14
|
+
blocked: true,
|
|
15
|
+
waitMs: Math.max(0, block.blockedUntil - now),
|
|
16
|
+
reason: block.reason,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
return { blocked: false, waitMs: 0, reason: null };
|
|
20
|
+
}
|
|
21
|
+
export function buildModelCapabilityMatrix(input) {
|
|
22
|
+
const now = input.now ?? Date.now();
|
|
23
|
+
const models = (input.models?.length ? input.models : Object.keys(MODEL_PROFILES))
|
|
24
|
+
.map((model) => resolveNormalizedModel(model))
|
|
25
|
+
.filter((model, index, all) => all.indexOf(model) === index)
|
|
26
|
+
.sort();
|
|
27
|
+
const accounts = input.storage?.accounts ?? [];
|
|
28
|
+
const entries = [];
|
|
29
|
+
for (const [index, account] of accounts.entries()) {
|
|
30
|
+
const accountKey = getAccountPolicyKey(account, index);
|
|
31
|
+
const entitlementKeys = [
|
|
32
|
+
accountKey,
|
|
33
|
+
resolveEntitlementAccountKey({
|
|
34
|
+
accountId: account.accountId,
|
|
35
|
+
email: account.email,
|
|
36
|
+
index,
|
|
37
|
+
}),
|
|
38
|
+
];
|
|
39
|
+
for (const model of models) {
|
|
40
|
+
const profile = MODEL_PROFILES[model] ?? MODEL_PROFILES[resolveNormalizedModel(model)];
|
|
41
|
+
if (!profile)
|
|
42
|
+
continue;
|
|
43
|
+
const entitlement = getEntitlementBlock(input.entitlements, entitlementKeys, profile.normalizedModel, now);
|
|
44
|
+
const capabilityPolicy = input.capabilityPolicy?.getSnapshot(accountKey, profile.normalizedModel) ??
|
|
45
|
+
null;
|
|
46
|
+
const capabilityBoost = input.capabilityPolicy?.getBoost(accountKey, profile.normalizedModel, now) ??
|
|
47
|
+
0;
|
|
48
|
+
const quota = input.quotaCache && input.storage
|
|
49
|
+
? findQuotaCacheEntryForAccount(input.quotaCache, account, input.storage.accounts)
|
|
50
|
+
: null;
|
|
51
|
+
const reasons = [];
|
|
52
|
+
if (account.enabled === false)
|
|
53
|
+
reasons.push("account disabled");
|
|
54
|
+
if (entitlement.blocked) {
|
|
55
|
+
reasons.push(`entitlement blocked: ${entitlement.reason ?? "unknown"}`);
|
|
56
|
+
}
|
|
57
|
+
if (capabilityPolicy && capabilityPolicy.unsupported > 0) {
|
|
58
|
+
reasons.push("capability policy has unsupported failures");
|
|
59
|
+
}
|
|
60
|
+
if (quota?.status === 429)
|
|
61
|
+
reasons.push("quota cache is rate-limited");
|
|
62
|
+
entries.push({
|
|
63
|
+
accountIndex: index + 1,
|
|
64
|
+
accountLabel: `Account ${index + 1}`,
|
|
65
|
+
accountKey,
|
|
66
|
+
model,
|
|
67
|
+
normalizedModel: profile.normalizedModel,
|
|
68
|
+
promptFamily: profile.promptFamily,
|
|
69
|
+
defaultReasoningEffort: profile.defaultReasoningEffort,
|
|
70
|
+
supportedReasoningEfforts: profile.supportedReasoningEfforts,
|
|
71
|
+
capabilities: profile.capabilities,
|
|
72
|
+
entitlementBlocked: entitlement.blocked,
|
|
73
|
+
entitlementReason: entitlement.reason,
|
|
74
|
+
entitlementWaitMs: entitlement.waitMs,
|
|
75
|
+
capabilityPolicy,
|
|
76
|
+
capabilityBoost,
|
|
77
|
+
quota,
|
|
78
|
+
available: reasons.length === 0,
|
|
79
|
+
reasons,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
generatedAt: now,
|
|
85
|
+
models,
|
|
86
|
+
entries,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=model-capability-matrix.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-capability-matrix.js","sourceRoot":"","sources":["../../lib/model-capability-matrix.ts"],"names":[],"mappings":"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"}
|