@opengeni/codex 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-2ESTGQ57.js +54 -0
- package/dist/chunk-2ESTGQ57.js.map +1 -0
- package/dist/constants.d.ts +24 -0
- package/dist/constants.js +49 -0
- package/dist/constants.js.map +1 -0
- package/dist/index.d.ts +267 -0
- package/dist/index.js +879 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -0
- package/src/api-client.ts +54 -0
- package/src/billing.ts +15 -0
- package/src/constants.ts +57 -0
- package/src/device-code.ts +111 -0
- package/src/fetch.ts +337 -0
- package/src/index.ts +10 -0
- package/src/mcp-sanitize.ts +290 -0
- package/src/normalize.ts +132 -0
- package/src/refresh.ts +124 -0
- package/src/request-context.ts +50 -0
- package/src/usage-normalize.ts +263 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,879 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CODEX_APPS_MCP_SERVER_ID,
|
|
3
|
+
CODEX_APPS_MCP_SERVER_NAME,
|
|
4
|
+
CODEX_APPS_MCP_URL,
|
|
5
|
+
CODEX_APPS_REQUIRED_SCOPES,
|
|
6
|
+
CODEX_APPS_STARTUP_TIMEOUT_MS,
|
|
7
|
+
CODEX_AUTH_BASE,
|
|
8
|
+
CODEX_CLIENT_ID,
|
|
9
|
+
CODEX_CLIENT_VERSION,
|
|
10
|
+
CODEX_DEVICE_REDIRECT_URI,
|
|
11
|
+
CODEX_DEVICE_VERIFICATION_URL,
|
|
12
|
+
CODEX_FALLBACK_MODEL_SLUGS,
|
|
13
|
+
CODEX_ID_TOKEN_AUTH_CLAIM,
|
|
14
|
+
CODEX_ISSUER,
|
|
15
|
+
CODEX_MODEL_ID_PREFIX,
|
|
16
|
+
CODEX_ORIGINATOR,
|
|
17
|
+
CODEX_PROVIDER_BASE_URL,
|
|
18
|
+
CODEX_PROVIDER_ID,
|
|
19
|
+
CODEX_REFRESH_FALLBACK_MS,
|
|
20
|
+
CODEX_REFRESH_WINDOW_MS,
|
|
21
|
+
CODEX_RESPONSES_BASE,
|
|
22
|
+
CODEX_TOKEN_URL,
|
|
23
|
+
CODEX_WHAM_BASE
|
|
24
|
+
} from "./chunk-2ESTGQ57.js";
|
|
25
|
+
|
|
26
|
+
// src/billing.ts
|
|
27
|
+
function isCodexBilledModel(model) {
|
|
28
|
+
return typeof model === "string" && model.startsWith(CODEX_MODEL_ID_PREFIX);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// src/device-code.ts
|
|
32
|
+
var CodexDeviceError = class extends Error {
|
|
33
|
+
constructor(message) {
|
|
34
|
+
super(message);
|
|
35
|
+
this.name = "CodexDeviceError";
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
async function startDeviceCode(fetchImpl = fetch) {
|
|
39
|
+
const res = await fetchImpl(`${CODEX_AUTH_BASE}/deviceauth/usercode`, {
|
|
40
|
+
method: "POST",
|
|
41
|
+
headers: { "Content-Type": "application/json" },
|
|
42
|
+
body: JSON.stringify({ client_id: CODEX_CLIENT_ID })
|
|
43
|
+
});
|
|
44
|
+
if (res.status === 404) {
|
|
45
|
+
throw new CodexDeviceError("device code login is not enabled for this Codex server");
|
|
46
|
+
}
|
|
47
|
+
if (!res.ok) {
|
|
48
|
+
throw new CodexDeviceError(`device code request failed with status ${res.status}`);
|
|
49
|
+
}
|
|
50
|
+
const body = await res.json();
|
|
51
|
+
return {
|
|
52
|
+
deviceAuthId: body.device_auth_id,
|
|
53
|
+
userCode: body.user_code ?? body.usercode ?? "",
|
|
54
|
+
verificationUri: CODEX_DEVICE_VERIFICATION_URL,
|
|
55
|
+
intervalSeconds: normalizeInterval(body.interval)
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function normalizeInterval(raw) {
|
|
59
|
+
const n = typeof raw === "string" ? Number.parseInt(raw.trim(), 10) : raw;
|
|
60
|
+
return typeof n === "number" && Number.isFinite(n) && n >= 1 ? n : 5;
|
|
61
|
+
}
|
|
62
|
+
async function pollDeviceCode(input, fetchImpl = fetch) {
|
|
63
|
+
const res = await fetchImpl(`${CODEX_AUTH_BASE}/deviceauth/token`, {
|
|
64
|
+
method: "POST",
|
|
65
|
+
headers: { "Content-Type": "application/json" },
|
|
66
|
+
body: JSON.stringify({ device_auth_id: input.deviceAuthId, user_code: input.userCode })
|
|
67
|
+
});
|
|
68
|
+
if (res.ok) {
|
|
69
|
+
const body = await res.json();
|
|
70
|
+
return { status: "authorized", authorizationCode: body.authorization_code, codeVerifier: body.code_verifier };
|
|
71
|
+
}
|
|
72
|
+
if (res.status === 403 || res.status === 404) {
|
|
73
|
+
return { status: "pending" };
|
|
74
|
+
}
|
|
75
|
+
throw new CodexDeviceError(`device auth failed with status ${res.status}`);
|
|
76
|
+
}
|
|
77
|
+
async function exchangeDeviceCode(input, fetchImpl = fetch) {
|
|
78
|
+
const form = new URLSearchParams({
|
|
79
|
+
grant_type: "authorization_code",
|
|
80
|
+
code: input.authorizationCode,
|
|
81
|
+
redirect_uri: CODEX_DEVICE_REDIRECT_URI,
|
|
82
|
+
client_id: CODEX_CLIENT_ID,
|
|
83
|
+
code_verifier: input.codeVerifier
|
|
84
|
+
});
|
|
85
|
+
const res = await fetchImpl(CODEX_TOKEN_URL, {
|
|
86
|
+
method: "POST",
|
|
87
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
88
|
+
body: form.toString()
|
|
89
|
+
});
|
|
90
|
+
if (!res.ok) {
|
|
91
|
+
throw new CodexDeviceError(`device code exchange failed with status ${res.status}`);
|
|
92
|
+
}
|
|
93
|
+
const body = await res.json();
|
|
94
|
+
return { idToken: body.id_token, accessToken: body.access_token, refreshToken: body.refresh_token };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// src/refresh.ts
|
|
98
|
+
var CodexReloginRequired = class extends Error {
|
|
99
|
+
constructor(message) {
|
|
100
|
+
super(message);
|
|
101
|
+
this.name = "CodexReloginRequired";
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
var CodexRefreshTransient = class extends Error {
|
|
105
|
+
constructor(message) {
|
|
106
|
+
super(message);
|
|
107
|
+
this.name = "CodexRefreshTransient";
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
async function refreshCodexToken(refreshToken, fetchImpl = fetch) {
|
|
111
|
+
const res = await fetchImpl(CODEX_TOKEN_URL, {
|
|
112
|
+
method: "POST",
|
|
113
|
+
headers: { "Content-Type": "application/json" },
|
|
114
|
+
body: JSON.stringify({ client_id: CODEX_CLIENT_ID, grant_type: "refresh_token", refresh_token: refreshToken })
|
|
115
|
+
});
|
|
116
|
+
const text = await res.text();
|
|
117
|
+
if (!res.ok) {
|
|
118
|
+
const code = extractRefreshErrorCode(text);
|
|
119
|
+
const msg = code ? PERMANENT_REFRESH_FAILURES[code] : void 0;
|
|
120
|
+
if (msg) {
|
|
121
|
+
throw new CodexReloginRequired(msg);
|
|
122
|
+
}
|
|
123
|
+
if (res.status === 401) {
|
|
124
|
+
throw new CodexReloginRequired("Your Codex session could not be refreshed. Please disconnect and sign in again.");
|
|
125
|
+
}
|
|
126
|
+
throw new CodexRefreshTransient(`Failed to refresh Codex token: ${res.status}`);
|
|
127
|
+
}
|
|
128
|
+
const body = JSON.parse(text);
|
|
129
|
+
return { idToken: body.id_token, accessToken: body.access_token, refreshToken: body.refresh_token };
|
|
130
|
+
}
|
|
131
|
+
var PERMANENT_REFRESH_FAILURES = {
|
|
132
|
+
refresh_token_expired: "Your Codex refresh token has expired. Please disconnect and sign in again.",
|
|
133
|
+
refresh_token_reused: "Your Codex refresh token was already used. Please disconnect and sign in again.",
|
|
134
|
+
refresh_token_invalidated: "Your Codex refresh token was revoked. Please disconnect and sign in again.",
|
|
135
|
+
invalid_grant: "Your Codex session is no longer valid. Please disconnect and sign in again."
|
|
136
|
+
};
|
|
137
|
+
function extractRefreshErrorCode(text) {
|
|
138
|
+
try {
|
|
139
|
+
const o = JSON.parse(text);
|
|
140
|
+
const err = o.error;
|
|
141
|
+
if (typeof err === "string") {
|
|
142
|
+
return err;
|
|
143
|
+
}
|
|
144
|
+
if (err && typeof err === "object") {
|
|
145
|
+
const e = err;
|
|
146
|
+
if (typeof e.code === "string") return e.code;
|
|
147
|
+
if (typeof e.type === "string") return e.type;
|
|
148
|
+
}
|
|
149
|
+
if (typeof o.code === "string") return o.code;
|
|
150
|
+
if (typeof o.type === "string") return o.type;
|
|
151
|
+
} catch {
|
|
152
|
+
}
|
|
153
|
+
return void 0;
|
|
154
|
+
}
|
|
155
|
+
function decodeJwtPayload(jwt) {
|
|
156
|
+
const part = jwt.split(".")[1];
|
|
157
|
+
if (!part) {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
try {
|
|
161
|
+
const json = Buffer.from(part.replace(/-/g, "+").replace(/_/g, "/"), "base64").toString("utf8");
|
|
162
|
+
return JSON.parse(json);
|
|
163
|
+
} catch {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function accessTokenExpiry(accessToken) {
|
|
168
|
+
const payload = decodeJwtPayload(accessToken);
|
|
169
|
+
return typeof payload?.exp === "number" ? new Date(payload.exp * 1e3) : null;
|
|
170
|
+
}
|
|
171
|
+
function parseIdToken(idToken) {
|
|
172
|
+
const payload = decodeJwtPayload(idToken);
|
|
173
|
+
const auth = payload?.[CODEX_ID_TOKEN_AUTH_CLAIM] ?? {};
|
|
174
|
+
return {
|
|
175
|
+
chatgptAccountId: typeof auth.chatgpt_account_id === "string" ? auth.chatgpt_account_id : null,
|
|
176
|
+
planType: typeof auth.chatgpt_plan_type === "string" ? auth.chatgpt_plan_type : null,
|
|
177
|
+
isFedramp: auth.chatgpt_account_is_fedramp === true,
|
|
178
|
+
// The user's own email (standard OIDC `email` claim on the id_token); a
|
|
179
|
+
// non-secret display field for the accounts UI. Null when absent.
|
|
180
|
+
email: typeof payload?.email === "string" ? payload.email : null
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// src/normalize.ts
|
|
185
|
+
var MINIMAL = "minimal";
|
|
186
|
+
var CODEX_ALLOWED_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
187
|
+
"model",
|
|
188
|
+
"instructions",
|
|
189
|
+
"input",
|
|
190
|
+
"tools",
|
|
191
|
+
"tool_choice",
|
|
192
|
+
"parallel_tool_calls",
|
|
193
|
+
"reasoning",
|
|
194
|
+
"store",
|
|
195
|
+
"stream",
|
|
196
|
+
"include",
|
|
197
|
+
"prompt_cache_key",
|
|
198
|
+
"text"
|
|
199
|
+
]);
|
|
200
|
+
function normalizeCodexRequestBody(body, resolveModel) {
|
|
201
|
+
body.store = false;
|
|
202
|
+
body.stream = true;
|
|
203
|
+
const include = Array.isArray(body.include) ? body.include.filter((v) => typeof v === "string") : [];
|
|
204
|
+
if (!include.includes("reasoning.encrypted_content")) {
|
|
205
|
+
include.push("reasoning.encrypted_content");
|
|
206
|
+
}
|
|
207
|
+
body.include = include;
|
|
208
|
+
const reasoning = body.reasoning;
|
|
209
|
+
if (reasoning && reasoning.effort === MINIMAL) {
|
|
210
|
+
reasoning.effort = "low";
|
|
211
|
+
}
|
|
212
|
+
if (typeof body.model === "string") {
|
|
213
|
+
body.model = resolveModel(body.model);
|
|
214
|
+
}
|
|
215
|
+
if (Array.isArray(body.input)) {
|
|
216
|
+
for (const item of body.input) {
|
|
217
|
+
if (!item || typeof item !== "object") {
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
const record = item;
|
|
221
|
+
if ("id" in record) {
|
|
222
|
+
delete record.id;
|
|
223
|
+
}
|
|
224
|
+
if (record.type === "tool_search_call" && typeof record.arguments === "string") {
|
|
225
|
+
try {
|
|
226
|
+
const parsed = JSON.parse(record.arguments);
|
|
227
|
+
record.arguments = parsed && typeof parsed === "object" ? parsed : {};
|
|
228
|
+
} catch {
|
|
229
|
+
record.arguments = {};
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
if (Array.isArray(body.tools)) {
|
|
235
|
+
body.tools = body.tools.filter(
|
|
236
|
+
(t) => !(t && typeof t === "object" && t.type === "mcp")
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
for (const key of Object.keys(body)) {
|
|
240
|
+
if (!CODEX_ALLOWED_TOP_LEVEL_KEYS.has(key)) {
|
|
241
|
+
delete body[key];
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return body;
|
|
245
|
+
}
|
|
246
|
+
function buildModelResolver(liveSlugs, fallbackSlug) {
|
|
247
|
+
return (requested) => {
|
|
248
|
+
const stripped = requested.includes("/") ? requested.slice(requested.indexOf("/") + 1) : requested;
|
|
249
|
+
let best = "";
|
|
250
|
+
for (const slug of liveSlugs) {
|
|
251
|
+
if (stripped.startsWith(slug) && slug.length > best.length) {
|
|
252
|
+
best = slug;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return best || fallbackSlug;
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// src/usage-normalize.ts
|
|
260
|
+
import * as z from "zod/v4";
|
|
261
|
+
var CODEX_FIVE_HOUR_WINDOW_SECONDS = 18e3;
|
|
262
|
+
var CODEX_WEEKLY_WINDOW_SECONDS = 604800;
|
|
263
|
+
function buildCodexUsageWindowFromCache(usedPercent, resetAt, limitWindowSeconds) {
|
|
264
|
+
if (typeof usedPercent !== "number") {
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
const percent = clampPercent(usedPercent);
|
|
268
|
+
const resetDate = resetAt ? new Date(resetAt) : null;
|
|
269
|
+
const resetIso = resetDate && !Number.isNaN(resetDate.getTime()) ? resetDate.toISOString() : null;
|
|
270
|
+
const resetAfterSeconds = resetDate && !Number.isNaN(resetDate.getTime()) ? Math.max(0, Math.round((resetDate.getTime() - Date.now()) / 1e3)) : null;
|
|
271
|
+
return {
|
|
272
|
+
used: percent,
|
|
273
|
+
limit: 100,
|
|
274
|
+
remaining: 100 - percent,
|
|
275
|
+
percent,
|
|
276
|
+
resetAt: resetIso,
|
|
277
|
+
resetAfterSeconds,
|
|
278
|
+
limitWindowSeconds
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
var windowSchema = z.object({
|
|
282
|
+
used_percent: z.number().optional(),
|
|
283
|
+
reset_after_seconds: z.number().optional(),
|
|
284
|
+
reset_at: z.number().optional(),
|
|
285
|
+
limit_window_seconds: z.number().optional()
|
|
286
|
+
}).nullish();
|
|
287
|
+
var rateLimitSchema = z.object({
|
|
288
|
+
allowed: z.boolean().optional(),
|
|
289
|
+
limit_reached: z.boolean().optional(),
|
|
290
|
+
primary_window: windowSchema,
|
|
291
|
+
secondary_window: windowSchema
|
|
292
|
+
}).nullish();
|
|
293
|
+
var additionalLimitSchema = z.object({
|
|
294
|
+
limit_name: z.string().optional(),
|
|
295
|
+
metered_feature: z.string().optional(),
|
|
296
|
+
primary_window: windowSchema,
|
|
297
|
+
secondary_window: windowSchema
|
|
298
|
+
});
|
|
299
|
+
var creditsSchema = z.object({
|
|
300
|
+
has_credits: z.boolean().optional(),
|
|
301
|
+
unlimited: z.boolean().optional(),
|
|
302
|
+
overage_limit_reached: z.boolean().optional(),
|
|
303
|
+
balance: z.union([z.string(), z.number()]).optional()
|
|
304
|
+
}).nullish();
|
|
305
|
+
var usageBodySchema = z.object({
|
|
306
|
+
plan_type: z.string().nullish(),
|
|
307
|
+
rate_limit: rateLimitSchema,
|
|
308
|
+
additional_limits: z.array(additionalLimitSchema).nullish(),
|
|
309
|
+
credits: creditsSchema
|
|
310
|
+
});
|
|
311
|
+
function clampPercent(value) {
|
|
312
|
+
if (!Number.isFinite(value)) return 0;
|
|
313
|
+
return Math.min(100, Math.max(0, Math.round(value)));
|
|
314
|
+
}
|
|
315
|
+
function normalizeWindow(w) {
|
|
316
|
+
if (!w || typeof w.used_percent !== "number") {
|
|
317
|
+
return null;
|
|
318
|
+
}
|
|
319
|
+
const percent = clampPercent(w.used_percent);
|
|
320
|
+
const resetAfterSeconds = typeof w.reset_after_seconds === "number" ? Math.max(0, Math.round(w.reset_after_seconds)) : null;
|
|
321
|
+
let resetAt = null;
|
|
322
|
+
if (typeof w.reset_at === "number") {
|
|
323
|
+
resetAt = new Date(w.reset_at * 1e3).toISOString();
|
|
324
|
+
} else if (resetAfterSeconds != null) {
|
|
325
|
+
resetAt = new Date(Date.now() + resetAfterSeconds * 1e3).toISOString();
|
|
326
|
+
}
|
|
327
|
+
return {
|
|
328
|
+
used: percent,
|
|
329
|
+
limit: 100,
|
|
330
|
+
remaining: 100 - percent,
|
|
331
|
+
percent,
|
|
332
|
+
resetAt,
|
|
333
|
+
resetAfterSeconds,
|
|
334
|
+
limitWindowSeconds: typeof w.limit_window_seconds === "number" ? w.limit_window_seconds : 0
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
function pickWindows(primary, secondary) {
|
|
338
|
+
let fiveHour = null;
|
|
339
|
+
let weekly = null;
|
|
340
|
+
const unplaced = [];
|
|
341
|
+
for (const [slot, raw] of [["primary", primary], ["secondary", secondary]]) {
|
|
342
|
+
const nw = normalizeWindow(raw);
|
|
343
|
+
if (!nw) continue;
|
|
344
|
+
if (nw.limitWindowSeconds === CODEX_WEEKLY_WINDOW_SECONDS) {
|
|
345
|
+
weekly = nw;
|
|
346
|
+
} else if (nw.limitWindowSeconds === CODEX_FIVE_HOUR_WINDOW_SECONDS) {
|
|
347
|
+
fiveHour = nw;
|
|
348
|
+
} else {
|
|
349
|
+
unplaced.push({ slot, window: nw });
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
for (const { slot, window } of unplaced) {
|
|
353
|
+
if (slot === "primary" && !fiveHour) fiveHour = window;
|
|
354
|
+
else if (slot === "secondary" && !weekly) weekly = window;
|
|
355
|
+
}
|
|
356
|
+
return { fiveHour, weekly };
|
|
357
|
+
}
|
|
358
|
+
function normalizeCodexUsage(httpStatus, rawPayload) {
|
|
359
|
+
const fetchedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
360
|
+
const parsed = usageBodySchema.safeParse(rawPayload);
|
|
361
|
+
const body = parsed.success ? parsed.data : null;
|
|
362
|
+
const base = {
|
|
363
|
+
status: "no-data",
|
|
364
|
+
planType: body?.plan_type ?? null,
|
|
365
|
+
fiveHour: null,
|
|
366
|
+
weekly: null,
|
|
367
|
+
limitReached: false,
|
|
368
|
+
fetchedAt
|
|
369
|
+
};
|
|
370
|
+
if (httpStatus >= 400 && httpStatus !== 404 || body == null) {
|
|
371
|
+
return { ...base, status: "error" };
|
|
372
|
+
}
|
|
373
|
+
const rate = body.rate_limit ?? null;
|
|
374
|
+
const { fiveHour, weekly } = pickWindows(rate?.primary_window ?? null, rate?.secondary_window ?? null);
|
|
375
|
+
const limitReached = !!(rate?.limit_reached || rate?.allowed === false) || (fiveHour?.percent ?? 0) >= 100 || (weekly?.percent ?? 0) >= 100;
|
|
376
|
+
const additionalLimits = body.additional_limits ? body.additional_limits.map((al) => {
|
|
377
|
+
const windows = pickWindows(al.primary_window ?? null, al.secondary_window ?? null);
|
|
378
|
+
return {
|
|
379
|
+
limitName: al.limit_name ?? "",
|
|
380
|
+
meteredFeature: al.metered_feature ?? "",
|
|
381
|
+
fiveHour: windows.fiveHour,
|
|
382
|
+
weekly: windows.weekly
|
|
383
|
+
};
|
|
384
|
+
}) : void 0;
|
|
385
|
+
const credits = body.credits ? {
|
|
386
|
+
hasCredits: body.credits.has_credits ?? false,
|
|
387
|
+
unlimited: body.credits.unlimited ?? false,
|
|
388
|
+
overageLimitReached: body.credits.overage_limit_reached ?? false,
|
|
389
|
+
balance: body.credits.balance != null ? String(body.credits.balance) : "0"
|
|
390
|
+
} : void 0;
|
|
391
|
+
let status;
|
|
392
|
+
if (httpStatus === 404 || limitReached) {
|
|
393
|
+
status = "limit_reached";
|
|
394
|
+
} else if (!fiveHour && !weekly) {
|
|
395
|
+
status = "no-data";
|
|
396
|
+
} else {
|
|
397
|
+
status = "ok";
|
|
398
|
+
}
|
|
399
|
+
return {
|
|
400
|
+
...base,
|
|
401
|
+
status,
|
|
402
|
+
fiveHour,
|
|
403
|
+
weekly,
|
|
404
|
+
limitReached,
|
|
405
|
+
...additionalLimits ? { additionalLimits } : {},
|
|
406
|
+
...credits ? { credits } : {}
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// src/api-client.ts
|
|
411
|
+
function subscriptionHeaders(a) {
|
|
412
|
+
return {
|
|
413
|
+
Authorization: `Bearer ${a.accessToken}`,
|
|
414
|
+
...a.chatgptAccountId ? { "ChatGPT-Account-ID": a.chatgptAccountId } : {},
|
|
415
|
+
originator: CODEX_ORIGINATOR,
|
|
416
|
+
"User-Agent": `${CODEX_ORIGINATOR}/${a.clientVersion}`,
|
|
417
|
+
version: a.clientVersion,
|
|
418
|
+
...a.isFedramp ? { "X-OpenAI-Fedramp": "true" } : {}
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
async function fetchCodexModels(a, fetchImpl = fetch) {
|
|
422
|
+
const res = await fetchImpl(`${CODEX_RESPONSES_BASE}/models?client_version=${encodeURIComponent(a.clientVersion)}`, {
|
|
423
|
+
method: "GET",
|
|
424
|
+
headers: subscriptionHeaders(a)
|
|
425
|
+
});
|
|
426
|
+
if (!res.ok) {
|
|
427
|
+
return { ok: false, status: res.status, slugs: [] };
|
|
428
|
+
}
|
|
429
|
+
const body = await res.json();
|
|
430
|
+
const slugs = (body.models ?? []).map((m) => m.slug).filter((s) => typeof s === "string");
|
|
431
|
+
return { ok: true, status: res.status, slugs };
|
|
432
|
+
}
|
|
433
|
+
async function fetchCodexUsage(a, fetchImpl = fetch) {
|
|
434
|
+
const res = await fetchImpl(`${CODEX_WHAM_BASE}/wham/usage`, {
|
|
435
|
+
method: "GET",
|
|
436
|
+
headers: subscriptionHeaders(a)
|
|
437
|
+
});
|
|
438
|
+
const payload = res.ok || res.status === 404 ? await res.json().catch(() => null) : null;
|
|
439
|
+
return { status: res.status, payload };
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// src/request-context.ts
|
|
443
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
444
|
+
var codexRequestStorage = new AsyncLocalStorage();
|
|
445
|
+
|
|
446
|
+
// src/fetch.ts
|
|
447
|
+
function parseIntHeader(value) {
|
|
448
|
+
if (value === null) {
|
|
449
|
+
return null;
|
|
450
|
+
}
|
|
451
|
+
const n = Number.parseInt(value.trim(), 10);
|
|
452
|
+
return Number.isFinite(n) ? n : null;
|
|
453
|
+
}
|
|
454
|
+
function resolveResetAt(headers, atKey, afterKey, nowMs) {
|
|
455
|
+
const at = parseIntHeader(headers.get(atKey));
|
|
456
|
+
if (at !== null) {
|
|
457
|
+
return new Date(at * 1e3);
|
|
458
|
+
}
|
|
459
|
+
const after = parseIntHeader(headers.get(afterKey));
|
|
460
|
+
if (after !== null) {
|
|
461
|
+
return new Date(nowMs + after * 1e3);
|
|
462
|
+
}
|
|
463
|
+
return new Date(nowMs);
|
|
464
|
+
}
|
|
465
|
+
function parseCodexUsageHeaders(headers) {
|
|
466
|
+
const primaryUsedPercent = parseIntHeader(headers.get("x-codex-primary-used-percent"));
|
|
467
|
+
const secondaryUsedPercent = parseIntHeader(headers.get("x-codex-secondary-used-percent"));
|
|
468
|
+
if (primaryUsedPercent === null || secondaryUsedPercent === null) {
|
|
469
|
+
return null;
|
|
470
|
+
}
|
|
471
|
+
const nowMs = Date.now();
|
|
472
|
+
return {
|
|
473
|
+
primaryUsedPercent,
|
|
474
|
+
primaryResetAt: resolveResetAt(headers, "x-codex-primary-reset-at", "x-codex-primary-reset-after-seconds", nowMs),
|
|
475
|
+
secondaryUsedPercent,
|
|
476
|
+
secondaryResetAt: resolveResetAt(headers, "x-codex-secondary-reset-at", "x-codex-secondary-reset-after-seconds", nowMs),
|
|
477
|
+
checkedAt: new Date(nowMs)
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
function codexSubscriptionFetch(base = globalThis.fetch) {
|
|
481
|
+
return async (input, init) => {
|
|
482
|
+
const ctx = codexRequestStorage.getStore();
|
|
483
|
+
if (!ctx) {
|
|
484
|
+
return base(input, init);
|
|
485
|
+
}
|
|
486
|
+
const rawUrl = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
|
|
487
|
+
const rewritten = rawUrl.replace(/(?<!\/codex)\/responses(\b|$)/, "/codex/responses$1");
|
|
488
|
+
const attempt = async (auth) => {
|
|
489
|
+
const headers = new Headers(init?.headers);
|
|
490
|
+
headers.set("Authorization", `Bearer ${auth.accessToken}`);
|
|
491
|
+
if (auth.chatgptAccountId) {
|
|
492
|
+
headers.set("ChatGPT-Account-ID", auth.chatgptAccountId);
|
|
493
|
+
}
|
|
494
|
+
headers.set("originator", CODEX_ORIGINATOR);
|
|
495
|
+
headers.set("User-Agent", `${CODEX_ORIGINATOR}/${ctx.clientVersion}`);
|
|
496
|
+
headers.set("version", ctx.clientVersion);
|
|
497
|
+
headers.set("accept", "text/event-stream");
|
|
498
|
+
headers.set("content-type", "application/json");
|
|
499
|
+
if (auth.isFedramp) {
|
|
500
|
+
headers.set("X-OpenAI-Fedramp", "true");
|
|
501
|
+
}
|
|
502
|
+
headers.delete("OpenAI-Beta");
|
|
503
|
+
headers.delete("x-api-key");
|
|
504
|
+
let callerWantsStream = true;
|
|
505
|
+
const nextInit = { ...init, headers };
|
|
506
|
+
if (typeof init?.body === "string") {
|
|
507
|
+
try {
|
|
508
|
+
const parsed = JSON.parse(init.body);
|
|
509
|
+
callerWantsStream = parsed.stream === true;
|
|
510
|
+
nextInit.body = JSON.stringify(normalizeCodexRequestBody(parsed, ctx.resolveModel));
|
|
511
|
+
} catch {
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
if (process.env.CODEX_DEBUG) {
|
|
515
|
+
const keys = typeof nextInit.body === "string" ? Object.keys(JSON.parse(nextInit.body)) : [];
|
|
516
|
+
console.error(`[codex-debug] POST ${rewritten} stream=${callerWantsStream} bodyKeys=[${keys.join(",")}]`);
|
|
517
|
+
}
|
|
518
|
+
const res2 = await base(rewritten, nextInit);
|
|
519
|
+
const usage = parseCodexUsageHeaders(res2.headers);
|
|
520
|
+
if (usage) {
|
|
521
|
+
ctx.onUsageHeaders?.(usage);
|
|
522
|
+
}
|
|
523
|
+
if (process.env.CODEX_DEBUG && !res2.ok) {
|
|
524
|
+
console.error(`[codex-debug] <- ${res2.status} ${await res2.clone().text()}`);
|
|
525
|
+
}
|
|
526
|
+
if (!res2.ok) {
|
|
527
|
+
return await bufferCodexErrorResponse(res2);
|
|
528
|
+
}
|
|
529
|
+
return callerWantsStream ? repairCodexStream(res2) : await sseToJsonResponse(res2);
|
|
530
|
+
};
|
|
531
|
+
let res = await attempt(await ctx.getToken());
|
|
532
|
+
if (res.status === 401) {
|
|
533
|
+
res = await attempt(await ctx.refresh());
|
|
534
|
+
}
|
|
535
|
+
return res;
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
var CODEX_USAGE_LIMIT_ERROR_TYPE = "usage_limit_reached";
|
|
539
|
+
function classifyCodexUsageLimitError(error) {
|
|
540
|
+
let cur = error;
|
|
541
|
+
for (let depth = 0; depth < 6 && cur && typeof cur === "object"; depth++) {
|
|
542
|
+
const e = cur;
|
|
543
|
+
const body = e.error && typeof e.error === "object" ? e.error : void 0;
|
|
544
|
+
const type = (typeof e.type === "string" ? e.type : void 0) ?? (typeof body?.type === "string" ? body.type : void 0);
|
|
545
|
+
const message = typeof e.message === "string" ? e.message : "";
|
|
546
|
+
const status = Number(e.status);
|
|
547
|
+
if (type === CODEX_USAGE_LIMIT_ERROR_TYPE || message.includes(CODEX_USAGE_LIMIT_ERROR_TYPE) || status === 429 && /usage limit/i.test(message)) {
|
|
548
|
+
const resets = (typeof body?.resets_in_seconds === "number" ? body.resets_in_seconds : void 0) ?? (typeof e.resets_in_seconds === "number" ? e.resets_in_seconds : void 0) ?? null;
|
|
549
|
+
return { resetsInSeconds: resets };
|
|
550
|
+
}
|
|
551
|
+
cur = e.cause;
|
|
552
|
+
}
|
|
553
|
+
return null;
|
|
554
|
+
}
|
|
555
|
+
async function bufferCodexErrorResponse(res) {
|
|
556
|
+
const bodyText = await res.text().catch(() => "");
|
|
557
|
+
const headers = new Headers(res.headers);
|
|
558
|
+
headers.set("content-type", "application/json");
|
|
559
|
+
headers.delete("content-length");
|
|
560
|
+
headers.delete("content-encoding");
|
|
561
|
+
let errorType;
|
|
562
|
+
try {
|
|
563
|
+
const parsed = JSON.parse(bodyText);
|
|
564
|
+
errorType = typeof parsed.error?.type === "string" ? parsed.error.type : void 0;
|
|
565
|
+
} catch {
|
|
566
|
+
}
|
|
567
|
+
if (errorType === CODEX_USAGE_LIMIT_ERROR_TYPE) {
|
|
568
|
+
headers.set("x-should-retry", "false");
|
|
569
|
+
}
|
|
570
|
+
return new Response(bodyText, { status: res.status, statusText: res.statusText, headers });
|
|
571
|
+
}
|
|
572
|
+
async function sseToJsonResponse(res) {
|
|
573
|
+
const text = await res.text();
|
|
574
|
+
let final = null;
|
|
575
|
+
const items = [];
|
|
576
|
+
for (const block of text.split("\n\n")) {
|
|
577
|
+
const data = block.split("\n").filter((l) => l.startsWith("data:")).map((l) => l.slice(5).trim()).join("\n");
|
|
578
|
+
if (!data || data === "[DONE]") {
|
|
579
|
+
continue;
|
|
580
|
+
}
|
|
581
|
+
try {
|
|
582
|
+
const ev = JSON.parse(data);
|
|
583
|
+
if (ev.type === "response.output_item.done" && ev.item !== void 0) {
|
|
584
|
+
items.push(ev.item);
|
|
585
|
+
} else if (ev.type === "response.completed" || ev.type === "response.done" || ev.type === "response.incomplete") {
|
|
586
|
+
final = ev.response ?? null;
|
|
587
|
+
}
|
|
588
|
+
} catch {
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
if (final && items.length > 0) {
|
|
592
|
+
final = { ...final, output: items };
|
|
593
|
+
}
|
|
594
|
+
if (process.env.CODEX_DEBUG) {
|
|
595
|
+
console.error(`[codex-debug] sse->json items=${items.length} outputLen=${Array.isArray(final?.output) ? final.output.length : "?"}`);
|
|
596
|
+
}
|
|
597
|
+
const headers = new Headers(res.headers);
|
|
598
|
+
headers.set("content-type", "application/json");
|
|
599
|
+
headers.delete("content-length");
|
|
600
|
+
return new Response(JSON.stringify(final ?? {}), { status: 200, headers });
|
|
601
|
+
}
|
|
602
|
+
function repairCodexStream(res) {
|
|
603
|
+
if (!res.body) {
|
|
604
|
+
return res;
|
|
605
|
+
}
|
|
606
|
+
const items = [];
|
|
607
|
+
const decoder = new TextDecoder();
|
|
608
|
+
const encoder = new TextEncoder();
|
|
609
|
+
let buffer = "";
|
|
610
|
+
const transform = new TransformStream({
|
|
611
|
+
transform(chunk, controller) {
|
|
612
|
+
buffer += decoder.decode(chunk, { stream: true });
|
|
613
|
+
let idx = buffer.indexOf("\n\n");
|
|
614
|
+
while (idx !== -1) {
|
|
615
|
+
const block = buffer.slice(0, idx);
|
|
616
|
+
buffer = buffer.slice(idx + 2);
|
|
617
|
+
controller.enqueue(encoder.encode(`${patchSseBlock(block, items)}
|
|
618
|
+
|
|
619
|
+
`));
|
|
620
|
+
idx = buffer.indexOf("\n\n");
|
|
621
|
+
}
|
|
622
|
+
},
|
|
623
|
+
flush(controller) {
|
|
624
|
+
if (buffer.length > 0) {
|
|
625
|
+
controller.enqueue(encoder.encode(patchSseBlock(buffer, items)));
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
});
|
|
629
|
+
const headers = new Headers(res.headers);
|
|
630
|
+
headers.delete("content-length");
|
|
631
|
+
return new Response(res.body.pipeThrough(transform), { status: res.status, headers });
|
|
632
|
+
}
|
|
633
|
+
function patchSseBlock(block, items) {
|
|
634
|
+
const lines = block.split("\n");
|
|
635
|
+
const dataStr = lines.filter((l) => l.startsWith("data:")).map((l) => l.slice(5).trim()).join("\n");
|
|
636
|
+
if (!dataStr || dataStr === "[DONE]") {
|
|
637
|
+
return block;
|
|
638
|
+
}
|
|
639
|
+
let ev;
|
|
640
|
+
try {
|
|
641
|
+
ev = JSON.parse(dataStr);
|
|
642
|
+
} catch {
|
|
643
|
+
return block;
|
|
644
|
+
}
|
|
645
|
+
if (ev.type === "response.output_item.done" && ev.item !== void 0) {
|
|
646
|
+
items.push(ev.item);
|
|
647
|
+
return block;
|
|
648
|
+
}
|
|
649
|
+
if ((ev.type === "response.completed" || ev.type === "response.done" || ev.type === "response.incomplete") && ev.response) {
|
|
650
|
+
const out = ev.response.output;
|
|
651
|
+
if ((!Array.isArray(out) || out.length === 0) && items.length > 0) {
|
|
652
|
+
ev.response = { ...ev.response, output: items };
|
|
653
|
+
const nonData = lines.filter((l) => !l.startsWith("data:"));
|
|
654
|
+
return [...nonData, `data: ${JSON.stringify(ev)}`].join("\n");
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
return block;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// src/mcp-sanitize.ts
|
|
661
|
+
var VALID_TOOL_NAME = /^[a-zA-Z0-9_-]+$/;
|
|
662
|
+
var MAX_TOOL_NAME_LEN = 64;
|
|
663
|
+
var RUNTIME_TOOL_NAME_PREFIX_LEN = CODEX_APPS_MCP_SERVER_ID.length + "__".length;
|
|
664
|
+
var EFFECTIVE_MAX_TOOL_NAME_LEN = MAX_TOOL_NAME_LEN - RUNTIME_TOOL_NAME_PREFIX_LEN;
|
|
665
|
+
function shortHash(input) {
|
|
666
|
+
let h = 5381;
|
|
667
|
+
for (let i = 0; i < input.length; i++) {
|
|
668
|
+
h = (h << 5) + h + input.charCodeAt(i) >>> 0;
|
|
669
|
+
}
|
|
670
|
+
return h.toString(36);
|
|
671
|
+
}
|
|
672
|
+
function capLength(candidate, original) {
|
|
673
|
+
if (candidate.length <= EFFECTIVE_MAX_TOOL_NAME_LEN) {
|
|
674
|
+
return candidate;
|
|
675
|
+
}
|
|
676
|
+
const suffix = `_${shortHash(original)}`;
|
|
677
|
+
return candidate.slice(0, Math.max(0, EFFECTIVE_MAX_TOOL_NAME_LEN - suffix.length)) + suffix;
|
|
678
|
+
}
|
|
679
|
+
var ToolNameMapper = class {
|
|
680
|
+
sanitizedToOriginal = /* @__PURE__ */ new Map();
|
|
681
|
+
used = /* @__PURE__ */ new Set();
|
|
682
|
+
/** Return a legal, unique name (<= EFFECTIVE_MAX_TOOL_NAME_LEN, so `<prefix>__name` <= 64) for `original`, recording the reverse mapping. */
|
|
683
|
+
sanitize(original) {
|
|
684
|
+
let candidate = VALID_TOOL_NAME.test(original) ? original : original.replace(/[^a-zA-Z0-9_-]/g, "_") || "tool";
|
|
685
|
+
candidate = capLength(candidate, original);
|
|
686
|
+
if (this.used.has(candidate) && this.sanitizedToOriginal.get(candidate) !== original) {
|
|
687
|
+
const base = candidate;
|
|
688
|
+
let n = 2;
|
|
689
|
+
do {
|
|
690
|
+
const suffix = `_${n++}`;
|
|
691
|
+
candidate = (base.length + suffix.length > EFFECTIVE_MAX_TOOL_NAME_LEN ? base.slice(0, EFFECTIVE_MAX_TOOL_NAME_LEN - suffix.length) : base) + suffix;
|
|
692
|
+
} while (this.used.has(candidate));
|
|
693
|
+
}
|
|
694
|
+
this.used.add(candidate);
|
|
695
|
+
this.sanitizedToOriginal.set(candidate, original);
|
|
696
|
+
return candidate;
|
|
697
|
+
}
|
|
698
|
+
/** Reverse a sanitized name back to the MCP server's original, if known. */
|
|
699
|
+
toOriginal(sanitized) {
|
|
700
|
+
return this.sanitizedToOriginal.get(sanitized);
|
|
701
|
+
}
|
|
702
|
+
};
|
|
703
|
+
function sanitizeToolsInRpcMessage(message, mapper, namespaceSink) {
|
|
704
|
+
if (!message || typeof message !== "object") {
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
const tools = message.result?.tools;
|
|
708
|
+
if (!Array.isArray(tools)) {
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
for (const tool of tools) {
|
|
712
|
+
if (!tool || typeof tool !== "object") {
|
|
713
|
+
continue;
|
|
714
|
+
}
|
|
715
|
+
const record = tool;
|
|
716
|
+
if ("outputSchema" in record) {
|
|
717
|
+
delete record.outputSchema;
|
|
718
|
+
}
|
|
719
|
+
if (typeof record.name === "string") {
|
|
720
|
+
if (namespaceSink && record.name.includes(".")) {
|
|
721
|
+
const namespace = record.name.slice(0, record.name.indexOf("."));
|
|
722
|
+
if (namespace) {
|
|
723
|
+
namespaceSink.add(namespace);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
record.name = mapper.sanitize(record.name);
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
function inlineStructuredContentInRpcMessage(message) {
|
|
731
|
+
if (!message || typeof message !== "object") {
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
const result = message.result;
|
|
735
|
+
if (!result || typeof result !== "object") {
|
|
736
|
+
return;
|
|
737
|
+
}
|
|
738
|
+
const record = result;
|
|
739
|
+
if (!("structuredContent" in record)) {
|
|
740
|
+
return;
|
|
741
|
+
}
|
|
742
|
+
const structured = record.structuredContent;
|
|
743
|
+
if (structured === void 0 || structured === null) {
|
|
744
|
+
return;
|
|
745
|
+
}
|
|
746
|
+
const text = typeof structured === "string" ? structured : JSON.stringify(structured);
|
|
747
|
+
const content = Array.isArray(record.content) ? [...record.content] : [];
|
|
748
|
+
content.push({ type: "text", text });
|
|
749
|
+
record.content = content;
|
|
750
|
+
}
|
|
751
|
+
function sanitizeMcpJsonBody(text, mapper = new ToolNameMapper(), namespaceSink) {
|
|
752
|
+
try {
|
|
753
|
+
const parsed = JSON.parse(text);
|
|
754
|
+
sanitizeToolsInRpcMessage(parsed, mapper, namespaceSink);
|
|
755
|
+
inlineStructuredContentInRpcMessage(parsed);
|
|
756
|
+
return JSON.stringify(parsed);
|
|
757
|
+
} catch {
|
|
758
|
+
return text;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
function sanitizeMcpSseBody(text, mapper = new ToolNameMapper(), namespaceSink) {
|
|
762
|
+
return text.split("\n").map((line) => {
|
|
763
|
+
if (!line.startsWith("data:")) {
|
|
764
|
+
return line;
|
|
765
|
+
}
|
|
766
|
+
const payload = line.slice("data:".length).trimStart();
|
|
767
|
+
try {
|
|
768
|
+
const parsed = JSON.parse(payload);
|
|
769
|
+
sanitizeToolsInRpcMessage(parsed, mapper, namespaceSink);
|
|
770
|
+
inlineStructuredContentInRpcMessage(parsed);
|
|
771
|
+
return `data: ${JSON.stringify(parsed)}`;
|
|
772
|
+
} catch {
|
|
773
|
+
return line;
|
|
774
|
+
}
|
|
775
|
+
}).join("\n");
|
|
776
|
+
}
|
|
777
|
+
function remapToolCallRequestBody(body, mapper) {
|
|
778
|
+
try {
|
|
779
|
+
const message = JSON.parse(body);
|
|
780
|
+
if (message.method !== "tools/call") {
|
|
781
|
+
return null;
|
|
782
|
+
}
|
|
783
|
+
const name = message.params?.name;
|
|
784
|
+
if (typeof name !== "string") {
|
|
785
|
+
return null;
|
|
786
|
+
}
|
|
787
|
+
const original = mapper.toOriginal(name);
|
|
788
|
+
if (original === void 0 || original === name) {
|
|
789
|
+
return null;
|
|
790
|
+
}
|
|
791
|
+
message.params.name = original;
|
|
792
|
+
return JSON.stringify(message);
|
|
793
|
+
} catch {
|
|
794
|
+
return null;
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
function codexAppsSanitizingFetch(base = globalThis.fetch, namespaceSink) {
|
|
798
|
+
const mapper = new ToolNameMapper();
|
|
799
|
+
return async (input, init) => {
|
|
800
|
+
let nextInit = init;
|
|
801
|
+
if (init && typeof init.body === "string" && (init.method ?? "GET").toUpperCase() === "POST") {
|
|
802
|
+
const remapped = remapToolCallRequestBody(init.body, mapper);
|
|
803
|
+
if (remapped !== null) {
|
|
804
|
+
nextInit = { ...init, body: remapped };
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
const res = await base(input, nextInit);
|
|
808
|
+
const method = (init?.method ?? (input instanceof Request ? input.method : "GET")).toUpperCase();
|
|
809
|
+
if (method !== "POST" || !res.ok || !res.body) {
|
|
810
|
+
return res;
|
|
811
|
+
}
|
|
812
|
+
const contentType = res.headers.get("content-type") ?? "";
|
|
813
|
+
const isJson = contentType.includes("application/json");
|
|
814
|
+
const isSse = contentType.includes("text/event-stream");
|
|
815
|
+
if (!isJson && !isSse) {
|
|
816
|
+
return res;
|
|
817
|
+
}
|
|
818
|
+
const originalBody = await res.text();
|
|
819
|
+
const sanitized = isJson ? sanitizeMcpJsonBody(originalBody, mapper, namespaceSink) : sanitizeMcpSseBody(originalBody, mapper, namespaceSink);
|
|
820
|
+
const headers = new Headers(res.headers);
|
|
821
|
+
headers.delete("content-length");
|
|
822
|
+
headers.delete("content-encoding");
|
|
823
|
+
return new Response(sanitized, { status: res.status, statusText: res.statusText, headers });
|
|
824
|
+
};
|
|
825
|
+
}
|
|
826
|
+
export {
|
|
827
|
+
CODEX_APPS_MCP_SERVER_ID,
|
|
828
|
+
CODEX_APPS_MCP_SERVER_NAME,
|
|
829
|
+
CODEX_APPS_MCP_URL,
|
|
830
|
+
CODEX_APPS_REQUIRED_SCOPES,
|
|
831
|
+
CODEX_APPS_STARTUP_TIMEOUT_MS,
|
|
832
|
+
CODEX_AUTH_BASE,
|
|
833
|
+
CODEX_CLIENT_ID,
|
|
834
|
+
CODEX_CLIENT_VERSION,
|
|
835
|
+
CODEX_DEVICE_REDIRECT_URI,
|
|
836
|
+
CODEX_DEVICE_VERIFICATION_URL,
|
|
837
|
+
CODEX_FALLBACK_MODEL_SLUGS,
|
|
838
|
+
CODEX_FIVE_HOUR_WINDOW_SECONDS,
|
|
839
|
+
CODEX_ID_TOKEN_AUTH_CLAIM,
|
|
840
|
+
CODEX_ISSUER,
|
|
841
|
+
CODEX_MODEL_ID_PREFIX,
|
|
842
|
+
CODEX_ORIGINATOR,
|
|
843
|
+
CODEX_PROVIDER_BASE_URL,
|
|
844
|
+
CODEX_PROVIDER_ID,
|
|
845
|
+
CODEX_REFRESH_FALLBACK_MS,
|
|
846
|
+
CODEX_REFRESH_WINDOW_MS,
|
|
847
|
+
CODEX_RESPONSES_BASE,
|
|
848
|
+
CODEX_TOKEN_URL,
|
|
849
|
+
CODEX_USAGE_LIMIT_ERROR_TYPE,
|
|
850
|
+
CODEX_WEEKLY_WINDOW_SECONDS,
|
|
851
|
+
CODEX_WHAM_BASE,
|
|
852
|
+
CodexDeviceError,
|
|
853
|
+
CodexRefreshTransient,
|
|
854
|
+
CodexReloginRequired,
|
|
855
|
+
ToolNameMapper,
|
|
856
|
+
accessTokenExpiry,
|
|
857
|
+
buildCodexUsageWindowFromCache,
|
|
858
|
+
buildModelResolver,
|
|
859
|
+
classifyCodexUsageLimitError,
|
|
860
|
+
codexAppsSanitizingFetch,
|
|
861
|
+
codexRequestStorage,
|
|
862
|
+
codexSubscriptionFetch,
|
|
863
|
+
decodeJwtPayload,
|
|
864
|
+
exchangeDeviceCode,
|
|
865
|
+
fetchCodexModels,
|
|
866
|
+
fetchCodexUsage,
|
|
867
|
+
isCodexBilledModel,
|
|
868
|
+
normalizeCodexRequestBody,
|
|
869
|
+
normalizeCodexUsage,
|
|
870
|
+
parseCodexUsageHeaders,
|
|
871
|
+
parseIdToken,
|
|
872
|
+
pollDeviceCode,
|
|
873
|
+
refreshCodexToken,
|
|
874
|
+
remapToolCallRequestBody,
|
|
875
|
+
sanitizeMcpJsonBody,
|
|
876
|
+
sanitizeMcpSseBody,
|
|
877
|
+
startDeviceCode
|
|
878
|
+
};
|
|
879
|
+
//# sourceMappingURL=index.js.map
|