@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.
@@ -0,0 +1,54 @@
1
+ // src/constants.ts
2
+ var CODEX_ISSUER = "https://auth.openai.com";
3
+ var CODEX_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
4
+ var CODEX_AUTH_BASE = `${CODEX_ISSUER}/api/accounts`;
5
+ var CODEX_TOKEN_URL = `${CODEX_ISSUER}/oauth/token`;
6
+ var CODEX_DEVICE_VERIFICATION_URL = `${CODEX_ISSUER}/codex/device`;
7
+ var CODEX_DEVICE_REDIRECT_URI = `${CODEX_ISSUER}/deviceauth/callback`;
8
+ var CODEX_RESPONSES_BASE = "https://chatgpt.com/backend-api/codex";
9
+ var CODEX_WHAM_BASE = "https://chatgpt.com/backend-api";
10
+ var CODEX_ORIGINATOR = "codex_cli_rs";
11
+ var CODEX_ID_TOKEN_AUTH_CLAIM = "https://api.openai.com/auth";
12
+ var CODEX_PROVIDER_ID = "codex-subscription";
13
+ var CODEX_PROVIDER_BASE_URL = "https://chatgpt.com/backend-api";
14
+ var CODEX_MODEL_ID_PREFIX = "codex/";
15
+ var CODEX_FALLBACK_MODEL_SLUGS = [
16
+ "gpt-5.5",
17
+ "gpt-5.4",
18
+ "gpt-5.4-mini",
19
+ "gpt-5.3-codex-spark"
20
+ ];
21
+ var CODEX_CLIENT_VERSION = "0.142.4";
22
+ var CODEX_REFRESH_WINDOW_MS = 5 * 60 * 1e3;
23
+ var CODEX_REFRESH_FALLBACK_MS = 8 * 24 * 60 * 60 * 1e3;
24
+ var CODEX_APPS_MCP_SERVER_ID = "codex_apps";
25
+ var CODEX_APPS_MCP_SERVER_NAME = "codex_apps";
26
+ var CODEX_APPS_MCP_URL = "https://chatgpt.com/backend-api/ps/mcp";
27
+ var CODEX_APPS_STARTUP_TIMEOUT_MS = 3e4;
28
+ var CODEX_APPS_REQUIRED_SCOPES = ["api.connectors.read", "api.connectors.invoke"];
29
+
30
+ export {
31
+ CODEX_ISSUER,
32
+ CODEX_CLIENT_ID,
33
+ CODEX_AUTH_BASE,
34
+ CODEX_TOKEN_URL,
35
+ CODEX_DEVICE_VERIFICATION_URL,
36
+ CODEX_DEVICE_REDIRECT_URI,
37
+ CODEX_RESPONSES_BASE,
38
+ CODEX_WHAM_BASE,
39
+ CODEX_ORIGINATOR,
40
+ CODEX_ID_TOKEN_AUTH_CLAIM,
41
+ CODEX_PROVIDER_ID,
42
+ CODEX_PROVIDER_BASE_URL,
43
+ CODEX_MODEL_ID_PREFIX,
44
+ CODEX_FALLBACK_MODEL_SLUGS,
45
+ CODEX_CLIENT_VERSION,
46
+ CODEX_REFRESH_WINDOW_MS,
47
+ CODEX_REFRESH_FALLBACK_MS,
48
+ CODEX_APPS_MCP_SERVER_ID,
49
+ CODEX_APPS_MCP_SERVER_NAME,
50
+ CODEX_APPS_MCP_URL,
51
+ CODEX_APPS_STARTUP_TIMEOUT_MS,
52
+ CODEX_APPS_REQUIRED_SCOPES
53
+ };
54
+ //# sourceMappingURL=chunk-2ESTGQ57.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/constants.ts"],"sourcesContent":["// Wire constants for the ChatGPT/Codex subscription backend.\n// Source: CODEX-SUBSCRIPTION-SPEC.md (verified against openai/codex codex-rs).\n\nexport const CODEX_ISSUER = \"https://auth.openai.com\";\nexport const CODEX_CLIENT_ID = \"app_EMoamEEZ73f0CkXaXp7hrann\"; // spec §1.1 (manager.rs:1444)\nexport const CODEX_AUTH_BASE = `${CODEX_ISSUER}/api/accounts`; // device endpoints (device_code_auth.rs:164)\nexport const CODEX_TOKEN_URL = `${CODEX_ISSUER}/oauth/token`; // exchange (form) + refresh (json)\nexport const CODEX_DEVICE_VERIFICATION_URL = `${CODEX_ISSUER}/codex/device`;\nexport const CODEX_DEVICE_REDIRECT_URI = `${CODEX_ISSUER}/deviceauth/callback`;\n\n// Model requests: base already includes /codex; client appends /responses, /models.\nexport const CODEX_RESPONSES_BASE = \"https://chatgpt.com/backend-api/codex\";\n// Usage lives on the WHAM base — NOT under /codex (verified, spec §1.8a).\nexport const CODEX_WHAM_BASE = \"https://chatgpt.com/backend-api\";\n\nexport const CODEX_ORIGINATOR = \"codex_cli_rs\"; // whitelisted originator (spec §1.2)\nexport const CODEX_ID_TOKEN_AUTH_CLAIM = \"https://api.openai.com/auth\";\n\n// Synthetic registry-provider identity. The provider's baseURL is the bare\n// /backend-api (NOT /codex) — codexSubscriptionFetch rewrites /responses ->\n// /codex/responses. Codex model ids are namespaced `codex/<slug>` so they never\n// collide with the built-in OpenAI provider's model ids; the fetch's resolveModel\n// strips the prefix before the slug reaches the backend.\nexport const CODEX_PROVIDER_ID = \"codex-subscription\";\nexport const CODEX_PROVIDER_BASE_URL = \"https://chatgpt.com/backend-api\";\nexport const CODEX_MODEL_ID_PREFIX = \"codex/\";\n\n// Offline fallback catalog. The live catalog from GET /models supersedes this\n// when wired; until then these are the selectable codex models and the\n// longest-prefix resolution targets. Confirmed live (2026-06) against a pro plan:\n// GET /codex/models returned exactly these (plus the internal codex-auto-review).\nexport const CODEX_FALLBACK_MODEL_SLUGS = [\n \"gpt-5.5\",\n \"gpt-5.4\",\n \"gpt-5.4-mini\",\n \"gpt-5.3-codex-spark\",\n] as const;\n\n// Sent as the `version` header and inside the User-Agent. Confirmed live: the\n// backend accepts the current codex CLI version; an older value risks /models\n// min_client_version filtering. Keep in step with the codex CLI releases.\nexport const CODEX_CLIENT_VERSION = \"0.142.4\";\n\nexport const CODEX_REFRESH_WINDOW_MS = 5 * 60 * 1000; // proactive refresh when within 5 min of exp (spec §1.1)\nexport const CODEX_REFRESH_FALLBACK_MS = 8 * 24 * 60 * 60 * 1000; // 8 days when exp is unparseable\n\n// ── Apps / connectors MCP (spec §1.10, §E) ───────────────────────────────────\n// One server-side MCP exposes ALL the user's ChatGPT/Codex connectors\n// (gmail/github/linear/slack/sentry/drive/calendar/…). Streamable HTTP, always.\nexport const CODEX_APPS_MCP_SERVER_ID = \"codex_apps\"; // tools surface as mcp__codex_apps__<tool>\nexport const CODEX_APPS_MCP_SERVER_NAME = \"codex_apps\"; // MCP `name` — MUST equal the id so the SDK namespaces tools as mcp__codex_apps__*\nexport const CODEX_APPS_MCP_URL = \"https://chatgpt.com/backend-api/ps/mcp\"; // live URL (NOT /codex, NOT the legacy /wham/apps)\nexport const CODEX_APPS_STARTUP_TIMEOUT_MS = 30_000; // startup_timeout 30s (spec §1.10) — maps to timeoutMs on this server only\n// Connector scopes that the apps MCP requires. Present ONLY when granted at\n// browser-authorize time; the device-code path CANNOT be confirmed to grant\n// them, so treat connector availability as runtime-discovered (spec §1.10 / §E).\nexport const CODEX_APPS_REQUIRED_SCOPES = [\"api.connectors.read\", \"api.connectors.invoke\"] as const;\n"],"mappings":";AAGO,IAAM,eAAe;AACrB,IAAM,kBAAkB;AACxB,IAAM,kBAAkB,GAAG,YAAY;AACvC,IAAM,kBAAkB,GAAG,YAAY;AACvC,IAAM,gCAAgC,GAAG,YAAY;AACrD,IAAM,4BAA4B,GAAG,YAAY;AAGjD,IAAM,uBAAuB;AAE7B,IAAM,kBAAkB;AAExB,IAAM,mBAAmB;AACzB,IAAM,4BAA4B;AAOlC,IAAM,oBAAoB;AAC1B,IAAM,0BAA0B;AAChC,IAAM,wBAAwB;AAM9B,IAAM,6BAA6B;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAKO,IAAM,uBAAuB;AAE7B,IAAM,0BAA0B,IAAI,KAAK;AACzC,IAAM,4BAA4B,IAAI,KAAK,KAAK,KAAK;AAKrD,IAAM,2BAA2B;AACjC,IAAM,6BAA6B;AACnC,IAAM,qBAAqB;AAC3B,IAAM,gCAAgC;AAItC,IAAM,6BAA6B,CAAC,uBAAuB,uBAAuB;","names":[]}
@@ -0,0 +1,24 @@
1
+ declare const CODEX_ISSUER = "https://auth.openai.com";
2
+ declare const CODEX_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
3
+ declare const CODEX_AUTH_BASE = "https://auth.openai.com/api/accounts";
4
+ declare const CODEX_TOKEN_URL = "https://auth.openai.com/oauth/token";
5
+ declare const CODEX_DEVICE_VERIFICATION_URL = "https://auth.openai.com/codex/device";
6
+ declare const CODEX_DEVICE_REDIRECT_URI = "https://auth.openai.com/deviceauth/callback";
7
+ declare const CODEX_RESPONSES_BASE = "https://chatgpt.com/backend-api/codex";
8
+ declare const CODEX_WHAM_BASE = "https://chatgpt.com/backend-api";
9
+ declare const CODEX_ORIGINATOR = "codex_cli_rs";
10
+ declare const CODEX_ID_TOKEN_AUTH_CLAIM = "https://api.openai.com/auth";
11
+ declare const CODEX_PROVIDER_ID = "codex-subscription";
12
+ declare const CODEX_PROVIDER_BASE_URL = "https://chatgpt.com/backend-api";
13
+ declare const CODEX_MODEL_ID_PREFIX = "codex/";
14
+ declare const CODEX_FALLBACK_MODEL_SLUGS: readonly ["gpt-5.5", "gpt-5.4", "gpt-5.4-mini", "gpt-5.3-codex-spark"];
15
+ declare const CODEX_CLIENT_VERSION = "0.142.4";
16
+ declare const CODEX_REFRESH_WINDOW_MS: number;
17
+ declare const CODEX_REFRESH_FALLBACK_MS: number;
18
+ declare const CODEX_APPS_MCP_SERVER_ID = "codex_apps";
19
+ declare const CODEX_APPS_MCP_SERVER_NAME = "codex_apps";
20
+ declare const CODEX_APPS_MCP_URL = "https://chatgpt.com/backend-api/ps/mcp";
21
+ declare const CODEX_APPS_STARTUP_TIMEOUT_MS = 30000;
22
+ declare const CODEX_APPS_REQUIRED_SCOPES: readonly ["api.connectors.read", "api.connectors.invoke"];
23
+
24
+ export { CODEX_APPS_MCP_SERVER_ID, CODEX_APPS_MCP_SERVER_NAME, CODEX_APPS_MCP_URL, CODEX_APPS_REQUIRED_SCOPES, CODEX_APPS_STARTUP_TIMEOUT_MS, CODEX_AUTH_BASE, CODEX_CLIENT_ID, CODEX_CLIENT_VERSION, CODEX_DEVICE_REDIRECT_URI, CODEX_DEVICE_VERIFICATION_URL, CODEX_FALLBACK_MODEL_SLUGS, CODEX_ID_TOKEN_AUTH_CLAIM, CODEX_ISSUER, CODEX_MODEL_ID_PREFIX, CODEX_ORIGINATOR, CODEX_PROVIDER_BASE_URL, CODEX_PROVIDER_ID, CODEX_REFRESH_FALLBACK_MS, CODEX_REFRESH_WINDOW_MS, CODEX_RESPONSES_BASE, CODEX_TOKEN_URL, CODEX_WHAM_BASE };
@@ -0,0 +1,49 @@
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
+ export {
26
+ CODEX_APPS_MCP_SERVER_ID,
27
+ CODEX_APPS_MCP_SERVER_NAME,
28
+ CODEX_APPS_MCP_URL,
29
+ CODEX_APPS_REQUIRED_SCOPES,
30
+ CODEX_APPS_STARTUP_TIMEOUT_MS,
31
+ CODEX_AUTH_BASE,
32
+ CODEX_CLIENT_ID,
33
+ CODEX_CLIENT_VERSION,
34
+ CODEX_DEVICE_REDIRECT_URI,
35
+ CODEX_DEVICE_VERIFICATION_URL,
36
+ CODEX_FALLBACK_MODEL_SLUGS,
37
+ CODEX_ID_TOKEN_AUTH_CLAIM,
38
+ CODEX_ISSUER,
39
+ CODEX_MODEL_ID_PREFIX,
40
+ CODEX_ORIGINATOR,
41
+ CODEX_PROVIDER_BASE_URL,
42
+ CODEX_PROVIDER_ID,
43
+ CODEX_REFRESH_FALLBACK_MS,
44
+ CODEX_REFRESH_WINDOW_MS,
45
+ CODEX_RESPONSES_BASE,
46
+ CODEX_TOKEN_URL,
47
+ CODEX_WHAM_BASE
48
+ };
49
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,267 @@
1
+ export { CODEX_APPS_MCP_SERVER_ID, CODEX_APPS_MCP_SERVER_NAME, CODEX_APPS_MCP_URL, CODEX_APPS_REQUIRED_SCOPES, CODEX_APPS_STARTUP_TIMEOUT_MS, CODEX_AUTH_BASE, CODEX_CLIENT_ID, CODEX_CLIENT_VERSION, CODEX_DEVICE_REDIRECT_URI, CODEX_DEVICE_VERIFICATION_URL, CODEX_FALLBACK_MODEL_SLUGS, CODEX_ID_TOKEN_AUTH_CLAIM, CODEX_ISSUER, CODEX_MODEL_ID_PREFIX, CODEX_ORIGINATOR, CODEX_PROVIDER_BASE_URL, CODEX_PROVIDER_ID, CODEX_REFRESH_FALLBACK_MS, CODEX_REFRESH_WINDOW_MS, CODEX_RESPONSES_BASE, CODEX_TOKEN_URL, CODEX_WHAM_BASE } from './constants.js';
2
+ import { AsyncLocalStorage } from 'node:async_hooks';
3
+
4
+ /**
5
+ * Pure NECESSARY condition for a Codex-billed turn: the model id is namespaced
6
+ * for the Codex subscription provider (`codex/<slug>`).
7
+ *
8
+ * This is NOT sufficient to bypass billing — an active, connected workspace
9
+ * credential and the deployment flag (`settings.codexSubscriptionEnabled`) are
10
+ * ALSO required (see `isCodexBilledTurn`/`workspaceCodexSubscriptionActive` in
11
+ * `@opengeni/db`). Used only as a cheap, synchronous short-circuit so the common
12
+ * non-codex path never issues a credential read.
13
+ */
14
+ declare function isCodexBilledModel(model: string | null | undefined): boolean;
15
+
16
+ type CodexFetch = (input: string | URL, init?: RequestInit) => Promise<Response>;
17
+ type CodexDeviceStart = {
18
+ deviceAuthId: string;
19
+ userCode: string;
20
+ verificationUri: string;
21
+ intervalSeconds: number;
22
+ };
23
+ type CodexTokens = {
24
+ idToken: string;
25
+ accessToken: string;
26
+ refreshToken: string;
27
+ };
28
+ type CodexPollResult = {
29
+ status: "pending";
30
+ } | {
31
+ status: "expired";
32
+ } | {
33
+ status: "authorized";
34
+ authorizationCode: string;
35
+ codeVerifier: string;
36
+ };
37
+ declare class CodexDeviceError extends Error {
38
+ constructor(message: string);
39
+ }
40
+ /** Step 1: POST {auth}/deviceauth/usercode {client_id}. device_code_auth.rs:67-95 */
41
+ declare function startDeviceCode(fetchImpl?: CodexFetch): Promise<CodexDeviceStart>;
42
+ /** Step 3 (single, non-blocking): POST {auth}/deviceauth/token. 403/404 => pending. device_code_auth.rs:106-145 */
43
+ declare function pollDeviceCode(input: {
44
+ deviceAuthId: string;
45
+ userCode: string;
46
+ }, fetchImpl?: CodexFetch): Promise<CodexPollResult>;
47
+ /** Step 4: POST {issuer}/oauth/token form-encoded grant_type=authorization_code. server.rs:732-766 */
48
+ declare function exchangeDeviceCode(input: {
49
+ authorizationCode: string;
50
+ codeVerifier: string;
51
+ }, fetchImpl?: CodexFetch): Promise<CodexTokens>;
52
+
53
+ /** Permanent — the workspace must reconnect (status => needs_relogin). */
54
+ declare class CodexReloginRequired extends Error {
55
+ constructor(message: string);
56
+ }
57
+ /** Transient — safe to retry later. */
58
+ declare class CodexRefreshTransient extends Error {
59
+ constructor(message: string);
60
+ }
61
+ /** Only present fields are returned (the server may rotate any subset). */
62
+ type CodexRefreshTokens = {
63
+ idToken?: string | undefined;
64
+ accessToken?: string | undefined;
65
+ refreshToken?: string | undefined;
66
+ };
67
+ /** POST {issuer}/oauth/token JSON {client_id, grant_type:"refresh_token", refresh_token}. manager.rs:1336-1340 */
68
+ declare function refreshCodexToken(refreshToken: string, fetchImpl?: CodexFetch): Promise<CodexRefreshTokens>;
69
+ /** Decode a JWT payload (base64url, no signature check). */
70
+ declare function decodeJwtPayload(jwt: string): Record<string, unknown> | null;
71
+ /** access-token `exp` claim -> Date | null. token_data.rs:101-105 */
72
+ declare function accessTokenExpiry(accessToken: string): Date | null;
73
+ /** id_token -> {chatgptAccountId, planType, isFedramp}. server.rs:827-832; token_data.rs:71-99 */
74
+ declare function parseIdToken(idToken: string): {
75
+ chatgptAccountId: string | null;
76
+ planType: string | null;
77
+ isFedramp: boolean;
78
+ email: string | null;
79
+ };
80
+
81
+ /** Mutates a parsed Responses request body in place and returns it. Pure + synchronous + unit-testable. */
82
+ declare function normalizeCodexRequestBody(body: Record<string, unknown>, resolveModel: (slug: string) => string): Record<string, unknown>;
83
+ /**
84
+ * Build a longest-prefix model resolver. Catalog slugs come from GET /models
85
+ * (api-client.ts). One leading `namespace/` segment is stripped first; an
86
+ * unknown slug returns the fallback (caller should log — spec §1.4 step 4).
87
+ */
88
+ declare function buildModelResolver(liveSlugs: readonly string[], fallbackSlug: string): (slug: string) => string;
89
+
90
+ /** The 5-hour (primary) window's `limit_window_seconds`. */
91
+ declare const CODEX_FIVE_HOUR_WINDOW_SECONDS = 18000;
92
+ /** The weekly (secondary) window's `limit_window_seconds`. */
93
+ declare const CODEX_WEEKLY_WINDOW_SECONDS = 604800;
94
+ /** One normalized usage window (applied to BOTH primary_window and secondary_window). */
95
+ type CodexUsageWindow = {
96
+ used: number;
97
+ limit: number;
98
+ remaining: number;
99
+ percent: number;
100
+ resetAt: string | null;
101
+ resetAfterSeconds: number | null;
102
+ limitWindowSeconds: number;
103
+ };
104
+ /** One additional (per-feature) limit (forward-compat; P2 renders nothing from it). */
105
+ type CodexAdditionalLimit = {
106
+ limitName: string;
107
+ meteredFeature: string;
108
+ fiveHour: CodexUsageWindow | null;
109
+ weekly: CodexUsageWindow | null;
110
+ };
111
+ type CodexUsageStatus = "ok" | "limit_reached" | "error" | "no-data";
112
+ /** The normalized usage payload — the P2/P3 contract. */
113
+ type CodexUsagePayload = {
114
+ status: CodexUsageStatus;
115
+ planType: string | null;
116
+ fiveHour: CodexUsageWindow | null;
117
+ weekly: CodexUsageWindow | null;
118
+ limitReached: boolean;
119
+ fetchedAt: string;
120
+ /** Present only on a refresh/auth failure path; carries the precise reason. */
121
+ reason?: "needs_relogin" | undefined;
122
+ additionalLimits?: CodexAdditionalLimit[] | undefined;
123
+ credits?: {
124
+ hasCredits: boolean;
125
+ unlimited: boolean;
126
+ overageLimitReached: boolean;
127
+ balance: string;
128
+ } | undefined;
129
+ };
130
+ /**
131
+ * Build a normalized window from the PERSISTED cache columns (used_percent +
132
+ * absolute reset timestamp). The same 0–100 synthesis as the live path, with the
133
+ * skew-free countdown derived from `resetAt − now` at read time. Returns null when
134
+ * there is no cached percent yet. `limitWindowSeconds` is the constant that
135
+ * identifies the window (18000 ⇒ 5h, 604800 ⇒ weekly).
136
+ */
137
+ declare function buildCodexUsageWindowFromCache(usedPercent: number | null | undefined, resetAt: Date | string | null | undefined, limitWindowSeconds: number): CodexUsageWindow | null;
138
+ /**
139
+ * Normalize a /wham/usage fetch result into the P2/P3 contract.
140
+ *
141
+ * @param httpStatus the HTTP status from fetchCodexUsage (404 ⇒ a limit body)
142
+ * @param rawPayload the parsed JSON body (or null when the body was unreadable)
143
+ */
144
+ declare function normalizeCodexUsage(httpStatus: number, rawPayload: unknown): CodexUsagePayload;
145
+
146
+ type CodexAuthHeaders = {
147
+ accessToken: string;
148
+ chatgptAccountId: string | null;
149
+ isFedramp: boolean;
150
+ clientVersion: string;
151
+ };
152
+ /** GET /codex/models — login-check + live catalog. A 200 means the token is accepted. spec §1.4/§F */
153
+ declare function fetchCodexModels(a: CodexAuthHeaders, fetchImpl?: CodexFetch): Promise<{
154
+ ok: boolean;
155
+ status: number;
156
+ slugs: string[];
157
+ }>;
158
+ /** GET /wham/usage — authoritative limits. NB the WHAM base is /backend-api, NOT /codex (spec §1.8a). */
159
+ declare function fetchCodexUsage(a: CodexAuthHeaders, fetchImpl?: CodexFetch): Promise<{
160
+ status: number;
161
+ payload: unknown;
162
+ }>;
163
+
164
+ type CodexTokenSnapshot = {
165
+ accessToken: string;
166
+ chatgptAccountId: string | null;
167
+ isFedramp: boolean;
168
+ };
169
+ /**
170
+ * Multi-account P4 (Part A): a full usage snapshot scraped FOR FREE from the
171
+ * `x-codex-primary-*` / `x-codex-secondary-*` response headers the codex backend
172
+ * stamps on every `/codex/responses` turn (success AND 429 hard-cap). Integer-
173
+ * identical to GET /wham/usage but with zero extra round-trip. parseCodexUsageHeaders
174
+ * returns this only when BOTH windows parse, so a write is always a full 5-column
175
+ * snapshot (no partial-window clobber). Shape mirrors db's CodexAccountUsageSnapshot
176
+ * (non-null here: a partial read is filtered to null upstream, never half-written).
177
+ */
178
+ type CodexUsageHeaderSnapshot = {
179
+ primaryUsedPercent: number;
180
+ primaryResetAt: Date;
181
+ secondaryUsedPercent: number;
182
+ secondaryResetAt: Date;
183
+ checkedAt: Date;
184
+ };
185
+ type CodexRequestContext = {
186
+ clientVersion: string;
187
+ /** Worker-supplied: proactive refresh + single-flight + db persist. */
188
+ getToken: () => Promise<CodexTokenSnapshot>;
189
+ /** Forced refresh used for the 401 retry. */
190
+ refresh: () => Promise<CodexTokenSnapshot>;
191
+ /** Model-slug resolver (longest-prefix against the live catalog). */
192
+ resolveModel: (slug: string) => string;
193
+ /**
194
+ * Multi-account P4 (Part A): fire-and-forget usage-header sink. Called by
195
+ * codexSubscriptionFetch on EVERY response (sync, non-throwing, never awaited)
196
+ * with the parsed full-window snapshot. The worker records the latest into the
197
+ * P2 usage cache once per turn in its `finally` — packages/codex stays db-free.
198
+ */
199
+ onUsageHeaders?: (snapshot: CodexUsageHeaderSnapshot) => void;
200
+ };
201
+ declare const codexRequestStorage: AsyncLocalStorage<CodexRequestContext>;
202
+
203
+ type FetchLike = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
204
+ /**
205
+ * Multi-account P4 (Part A): scrape the full usage snapshot the codex backend
206
+ * stamps on every `/codex/responses` response in `x-codex-primary-*` /
207
+ * `x-codex-secondary-*` headers (integer-identical to GET /wham/usage, for free).
208
+ *
209
+ * CRITICAL clobber-fix: return null unless BOTH windows expose a valid used-percent
210
+ * integer. recordCodexAccountUsage writes all five columns unconditionally, so a
211
+ * primary-only snapshot would null the weekly column. Both windows are always
212
+ * emitted together on `/codex/responses`; gating on both makes every write a full
213
+ * 5-column snapshot byte-identical to the poll path, and a malformed/absent header
214
+ * set simply no-ops (the /wham/usage poll fallback still covers it).
215
+ */
216
+ declare function parseCodexUsageHeaders(headers: Headers): CodexUsageHeaderSnapshot | null;
217
+ declare function codexSubscriptionFetch(base?: FetchLike): FetchLike;
218
+ /** The codex backend's hard-cap error type (ChatGPT/Codex usage limit reached). */
219
+ declare const CODEX_USAGE_LIMIT_ERROR_TYPE = "usage_limit_reached";
220
+ type CodexUsageLimitInfo = {
221
+ /** Seconds until the usage cap resets, when the backend reported it. */
222
+ resetsInSeconds: number | null;
223
+ };
224
+ /**
225
+ * Classify a thrown error as a ChatGPT/Codex usage-cap (429 usage_limit_reached)
226
+ * and extract the reset window. The SDK surfaces the codex backend's 429 as an
227
+ * OpenAI APIError whose `.type` (and `.error.type`) is `usage_limit_reached` and
228
+ * whose `.error.resets_in_seconds` carries the cap reset. Walks the cause chain
229
+ * and tolerates the message-only shape so it survives any SDK re-wrapping.
230
+ * Returns null for anything that is not a usage cap.
231
+ */
232
+ declare function classifyCodexUsageLimitError(error: unknown): CodexUsageLimitInfo | null;
233
+
234
+ /**
235
+ * Maps connector tool names to a Responses-API-legal charset and back. One
236
+ * instance per codex_apps transport (i.e. per turn): tools/list populates it,
237
+ * tools/call reads it. Idempotent across repeat listings.
238
+ */
239
+ declare class ToolNameMapper {
240
+ private readonly sanitizedToOriginal;
241
+ private readonly used;
242
+ /** Return a legal, unique name (<= EFFECTIVE_MAX_TOOL_NAME_LEN, so `<prefix>__name` <= 64) for `original`, recording the reverse mapping. */
243
+ sanitize(original: string): string;
244
+ /** Reverse a sanitized name back to the MCP server's original, if known. */
245
+ toOriginal(sanitized: string): string | undefined;
246
+ }
247
+ /** Sanitize a single JSON body (application/json MCP response). */
248
+ declare function sanitizeMcpJsonBody(text: string, mapper?: ToolNameMapper, namespaceSink?: Set<string>): string;
249
+ /** Sanitize an SSE body: each JSON-RPC message rides on a `data:` line. */
250
+ declare function sanitizeMcpSseBody(text: string, mapper?: ToolNameMapper, namespaceSink?: Set<string>): string;
251
+ /** Reverse a sanitized tools/call name back to the original; returns null if no rewrite is needed. */
252
+ declare function remapToolCallRequestBody(body: string, mapper: ToolNameMapper): string | null;
253
+ /**
254
+ * Wrap a base fetch so the codex_apps MCP transport is Responses-API-compatible:
255
+ * tools/list responses get their names sanitized + bad outputSchemas dropped (and
256
+ * the name mapping recorded), and tools/call requests get their name reversed back
257
+ * to the MCP server's original. Only the POST request/response is buffered; the
258
+ * long-lived GET notification SSE stream is passed through untouched.
259
+ *
260
+ * P4 (Part B.1): an optional `namespaceSink` Set accumulates the ORIGINAL-dotted
261
+ * connector namespaces seen across every tools/list this turn (captured before the
262
+ * dot is sanitized away). The worker reads the (live, by-reference) Set after the
263
+ * turn to cache the serving account's connector set — packages/codex stays db-free.
264
+ */
265
+ declare function codexAppsSanitizingFetch(base?: FetchLike, namespaceSink?: Set<string>): FetchLike;
266
+
267
+ export { CODEX_FIVE_HOUR_WINDOW_SECONDS, CODEX_USAGE_LIMIT_ERROR_TYPE, CODEX_WEEKLY_WINDOW_SECONDS, type CodexAdditionalLimit, type CodexAuthHeaders, CodexDeviceError, type CodexDeviceStart, type CodexFetch, type CodexPollResult, type CodexRefreshTokens, CodexRefreshTransient, CodexReloginRequired, type CodexRequestContext, type CodexTokenSnapshot, type CodexTokens, type CodexUsageHeaderSnapshot, type CodexUsageLimitInfo, type CodexUsagePayload, type CodexUsageStatus, type CodexUsageWindow, type FetchLike, ToolNameMapper, accessTokenExpiry, buildCodexUsageWindowFromCache, buildModelResolver, classifyCodexUsageLimitError, codexAppsSanitizingFetch, codexRequestStorage, codexSubscriptionFetch, decodeJwtPayload, exchangeDeviceCode, fetchCodexModels, fetchCodexUsage, isCodexBilledModel, normalizeCodexRequestBody, normalizeCodexUsage, parseCodexUsageHeaders, parseIdToken, pollDeviceCode, refreshCodexToken, remapToolCallRequestBody, sanitizeMcpJsonBody, sanitizeMcpSseBody, startDeviceCode };