@vostride/agent-qa-subscription-auth 0.2.3 → 0.2.5

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/index.js CHANGED
@@ -1,715 +1,625 @@
1
+ import { createAuthFetch, generatePKCE, generateState } from "@vostride/agent-qa-core";
2
+ import { createServer } from "node:http";
1
3
  // src/anthropic.ts
2
- import {
3
- generatePKCE
4
- } from "@vostride/agent-qa-core";
5
- var ANTHROPIC_CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
6
- var ANTHROPIC_TOKEN_URL = "https://console.anthropic.com/v1/oauth/token";
7
- var ANTHROPIC_REDIRECT_URI = "https://console.anthropic.com/oauth/code/callback";
8
- var ANTHROPIC_SCOPES = "org:create_api_key user:profile user:inference";
9
- var ANTHROPIC_BETA_FLAGS = "oauth-2025-04-20,interleaved-thinking-2025-05-14";
10
- var SYSTEM_PREFIX = "You are Claude Code, Anthropic's official CLI for Claude.";
11
- var TOOL_PREFIX = "mcp_";
12
- var AUTH_BASES = {
13
- max: "https://claude.ai/oauth/authorize",
14
- console: "https://console.anthropic.com/oauth/authorize"
4
+ const ANTHROPIC_CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
5
+ const ANTHROPIC_TOKEN_URL = "https://console.anthropic.com/v1/oauth/token";
6
+ const ANTHROPIC_REDIRECT_URI = "https://console.anthropic.com/oauth/code/callback";
7
+ const ANTHROPIC_SCOPES = "org:create_api_key user:profile user:inference";
8
+ const ANTHROPIC_BETA_FLAGS = "oauth-2025-04-20,interleaved-thinking-2025-05-14";
9
+ const SYSTEM_PREFIX = "You are Claude Code, Anthropic's official CLI for Claude.";
10
+ const TOOL_PREFIX = "mcp_";
11
+ const AUTH_BASES = {
12
+ max: "https://claude.ai/oauth/authorize",
13
+ console: "https://console.anthropic.com/oauth/authorize"
15
14
  };
16
15
  function anthropicAuthorizeUrl(options) {
17
- const base = AUTH_BASES[options.mode];
18
- const params = new URLSearchParams({
19
- code: "true",
20
- client_id: ANTHROPIC_CLIENT_ID,
21
- response_type: "code",
22
- redirect_uri: ANTHROPIC_REDIRECT_URI,
23
- scope: ANTHROPIC_SCOPES,
24
- code_challenge: options.pkce.challenge,
25
- code_challenge_method: "S256",
26
- state: options.pkce.verifier
27
- });
28
- return `${base}?${params.toString()}`;
16
+ return `${AUTH_BASES[options.mode]}?${new URLSearchParams({
17
+ code: "true",
18
+ client_id: ANTHROPIC_CLIENT_ID,
19
+ response_type: "code",
20
+ redirect_uri: ANTHROPIC_REDIRECT_URI,
21
+ scope: ANTHROPIC_SCOPES,
22
+ code_challenge: options.pkce.challenge,
23
+ code_challenge_method: "S256",
24
+ state: options.pkce.verifier
25
+ }).toString()}`;
29
26
  }
30
27
  function startAnthropicAuth() {
31
- const pkce = generatePKCE();
32
- return {
33
- authorizeUrl: anthropicAuthorizeUrl({ mode: "max", pkce }),
34
- sessionState: { verifier: pkce.verifier }
35
- };
28
+ const pkce = generatePKCE();
29
+ return {
30
+ authorizeUrl: anthropicAuthorizeUrl({
31
+ mode: "max",
32
+ pkce
33
+ }),
34
+ sessionState: { verifier: pkce.verifier }
35
+ };
36
36
  }
37
37
  function readVerifier(sessionState) {
38
- if (sessionState && typeof sessionState === "object" && typeof sessionState.verifier === "string") {
39
- return sessionState.verifier;
40
- }
41
- throw new Error("Anthropic subscription auth session is missing PKCE verifier.");
38
+ if (sessionState && typeof sessionState === "object" && typeof sessionState.verifier === "string") return sessionState.verifier;
39
+ throw new Error("Anthropic subscription auth session is missing PKCE verifier.");
42
40
  }
43
41
  async function exchangeAnthropicManualCode(ctx) {
44
- return await anthropicExchangeCode(ctx.code, { verifier: readVerifier(ctx.sessionState) });
42
+ return await anthropicExchangeCode(ctx.code, { verifier: readVerifier(ctx.sessionState) });
45
43
  }
46
44
  async function anthropicExchangeCode(codeWithState, pkce) {
47
- const [code, state] = codeWithState.split("#");
48
- const res = await globalThis.fetch(ANTHROPIC_TOKEN_URL, {
49
- method: "POST",
50
- headers: { "Content-Type": "application/json" },
51
- body: JSON.stringify({
52
- code,
53
- state: state ?? pkce.verifier,
54
- grant_type: "authorization_code",
55
- client_id: ANTHROPIC_CLIENT_ID,
56
- redirect_uri: ANTHROPIC_REDIRECT_URI,
57
- code_verifier: pkce.verifier
58
- })
59
- });
60
- if (!res.ok) {
61
- const text = await res.text();
62
- throw new Error(`Anthropic token exchange failed: ${text}`);
63
- }
64
- const json = await res.json();
65
- if (typeof json.access_token !== "string" || typeof json.refresh_token !== "string" || typeof json.expires_in !== "number") {
66
- throw new Error("Anthropic token exchange response is missing required fields");
67
- }
68
- return {
69
- access: json.access_token,
70
- refresh: json.refresh_token,
71
- expires: Date.now() + json.expires_in * 1e3
72
- };
45
+ const [code, state] = codeWithState.split("#");
46
+ const res = await globalThis.fetch(ANTHROPIC_TOKEN_URL, {
47
+ method: "POST",
48
+ headers: { "Content-Type": "application/json" },
49
+ body: JSON.stringify({
50
+ code,
51
+ state: state ?? pkce.verifier,
52
+ grant_type: "authorization_code",
53
+ client_id: ANTHROPIC_CLIENT_ID,
54
+ redirect_uri: ANTHROPIC_REDIRECT_URI,
55
+ code_verifier: pkce.verifier
56
+ })
57
+ });
58
+ if (!res.ok) {
59
+ const text = await res.text();
60
+ throw new Error(`Anthropic token exchange failed: ${text}`);
61
+ }
62
+ const json = await res.json();
63
+ if (typeof json.access_token !== "string" || typeof json.refresh_token !== "string" || typeof json.expires_in !== "number") throw new Error("Anthropic token exchange response is missing required fields");
64
+ return {
65
+ access: json.access_token,
66
+ refresh: json.refresh_token,
67
+ expires: Date.now() + json.expires_in * 1e3
68
+ };
73
69
  }
74
- var anthropicRefreshTokens = async (_provider, refreshToken) => {
75
- const res = await globalThis.fetch(ANTHROPIC_TOKEN_URL, {
76
- method: "POST",
77
- headers: { "Content-Type": "application/json" },
78
- body: JSON.stringify({
79
- grant_type: "refresh_token",
80
- refresh_token: refreshToken,
81
- client_id: ANTHROPIC_CLIENT_ID
82
- })
83
- });
84
- if (!res.ok) {
85
- const text = await res.text();
86
- throw new Error(`Anthropic token refresh failed: ${text}`);
87
- }
88
- const json = await res.json();
89
- if (typeof json.access_token !== "string" || typeof json.expires_in !== "number") {
90
- throw new Error("Anthropic token refresh response is missing required fields");
91
- }
92
- return {
93
- access: json.access_token,
94
- refresh: typeof json.refresh_token === "string" ? json.refresh_token : refreshToken,
95
- expires: Date.now() + json.expires_in * 1e3
96
- };
70
+ const anthropicRefreshTokens = async (_provider, refreshToken) => {
71
+ const res = await globalThis.fetch(ANTHROPIC_TOKEN_URL, {
72
+ method: "POST",
73
+ headers: { "Content-Type": "application/json" },
74
+ body: JSON.stringify({
75
+ grant_type: "refresh_token",
76
+ refresh_token: refreshToken,
77
+ client_id: ANTHROPIC_CLIENT_ID
78
+ })
79
+ });
80
+ if (!res.ok) {
81
+ const text = await res.text();
82
+ throw new Error(`Anthropic token refresh failed: ${text}`);
83
+ }
84
+ const json = await res.json();
85
+ if (typeof json.access_token !== "string" || typeof json.expires_in !== "number") throw new Error("Anthropic token refresh response is missing required fields");
86
+ return {
87
+ access: json.access_token,
88
+ refresh: typeof json.refresh_token === "string" ? json.refresh_token : refreshToken,
89
+ expires: Date.now() + json.expires_in * 1e3
90
+ };
97
91
  };
98
92
  function prefixToolName(name) {
99
- return typeof name === "string" && !name.startsWith(TOOL_PREFIX) ? `${TOOL_PREFIX}${name}` : name;
93
+ return typeof name === "string" && !name.startsWith(TOOL_PREFIX) ? `${TOOL_PREFIX}${name}` : name;
100
94
  }
101
95
  function stripToolNamePrefix(name) {
102
- return typeof name === "string" && name.startsWith(TOOL_PREFIX) ? name.slice(TOOL_PREFIX.length) : name;
96
+ return typeof name === "string" && name.startsWith(TOOL_PREFIX) ? name.slice(4) : name;
103
97
  }
104
98
  function createAnthropicAuthFetch(getTokens, onRefreshed) {
105
- return async (input, init) => {
106
- let tokens = await getTokens();
107
- if (tokens.expires < Date.now()) {
108
- tokens = await anthropicRefreshTokens("anthropic-subscription", tokens.refresh);
109
- await onRefreshed(tokens);
110
- }
111
- const headers = new Headers();
112
- if (input instanceof Request) {
113
- input.headers.forEach((value, key) => {
114
- headers.set(key, value);
115
- });
116
- }
117
- if (init?.headers) {
118
- if (init.headers instanceof Headers) {
119
- init.headers.forEach((value, key) => {
120
- headers.set(key, value);
121
- });
122
- } else if (Array.isArray(init.headers)) {
123
- for (const [key, value] of init.headers) {
124
- if (value !== void 0) headers.set(key, String(value));
125
- }
126
- } else {
127
- for (const [key, value] of Object.entries(init.headers)) {
128
- if (value !== void 0) headers.set(key, String(value));
129
- }
130
- }
131
- }
132
- const incoming = (headers.get("anthropic-beta") || "").split(",").map((b) => b.trim()).filter(Boolean);
133
- const required = ANTHROPIC_BETA_FLAGS.split(",");
134
- const merged = [.../* @__PURE__ */ new Set([...required, ...incoming])].join(",");
135
- headers.delete("authorization");
136
- headers.delete("x-api-key");
137
- headers.set("Authorization", `Bearer ${tokens.access}`);
138
- headers.set("anthropic-beta", merged);
139
- headers.set("user-agent", "claude-cli/2.1.2 (external, cli)");
140
- let body = init?.body;
141
- if (body && typeof body === "string") {
142
- try {
143
- const parsed = JSON.parse(body);
144
- if (parsed.system && Array.isArray(parsed.system)) {
145
- parsed.system = [{ type: "text", text: SYSTEM_PREFIX }, ...parsed.system];
146
- } else if (typeof parsed.system === "string") {
147
- parsed.system = SYSTEM_PREFIX + "\n\n" + parsed.system;
148
- } else if (!parsed.system) {
149
- parsed.system = [{ type: "text", text: SYSTEM_PREFIX }];
150
- }
151
- if (parsed.tools && Array.isArray(parsed.tools)) {
152
- parsed.tools = parsed.tools.map((tool) => ({
153
- ...tool,
154
- name: prefixToolName(tool.name)
155
- }));
156
- }
157
- if (parsed.messages && Array.isArray(parsed.messages)) {
158
- parsed.messages = parsed.messages.map((msg) => {
159
- if (msg.content && Array.isArray(msg.content)) {
160
- msg.content = msg.content.map((block) => {
161
- if (block.type === "tool_use" && block.name) {
162
- return { ...block, name: prefixToolName(block.name) };
163
- }
164
- return block;
165
- });
166
- }
167
- return msg;
168
- });
169
- }
170
- body = JSON.stringify(parsed);
171
- } catch {
172
- }
173
- }
174
- let url;
175
- if (typeof input === "string") url = input;
176
- else if (input instanceof URL) url = input.toString();
177
- else url = input.url;
178
- try {
179
- const parsed = new URL(url);
180
- if (parsed.pathname === "/v1/messages" && !parsed.searchParams.has("beta")) {
181
- parsed.searchParams.set("beta", "true");
182
- url = parsed.toString();
183
- }
184
- } catch {
185
- }
186
- const response = await globalThis.fetch(url, {
187
- ...init,
188
- body,
189
- headers
190
- });
191
- if (!response.ok) {
192
- const text = await response.text();
193
- return new Response(text, {
194
- status: response.status,
195
- statusText: response.statusText,
196
- headers: response.headers
197
- });
198
- }
199
- if (response.body) {
200
- const contentType = response.headers.get("content-type") ?? "";
201
- if (contentType.includes("application/json")) {
202
- const rawText = await response.text();
203
- const headers2 = new Headers(response.headers);
204
- headers2.delete("content-length");
205
- headers2.delete("content-encoding");
206
- try {
207
- const json = JSON.parse(rawText);
208
- rewriteToolUseNames(json);
209
- return new Response(JSON.stringify(json), {
210
- status: response.status,
211
- statusText: response.statusText,
212
- headers: headers2
213
- });
214
- } catch {
215
- return new Response(rawText, {
216
- status: response.status,
217
- statusText: response.statusText,
218
- headers: headers2
219
- });
220
- }
221
- }
222
- const stream = response.body.pipeThrough(createAnthropicToolNameTransform());
223
- return new Response(stream, {
224
- status: response.status,
225
- statusText: response.statusText,
226
- headers: response.headers
227
- });
228
- }
229
- return response;
230
- };
99
+ return async (input, init) => {
100
+ let tokens = await getTokens();
101
+ if (tokens.expires < Date.now()) {
102
+ tokens = await anthropicRefreshTokens("anthropic-subscription", tokens.refresh);
103
+ await onRefreshed(tokens);
104
+ }
105
+ const headers = new Headers();
106
+ if (input instanceof Request) input.headers.forEach((value, key) => {
107
+ headers.set(key, value);
108
+ });
109
+ if (init?.headers) {
110
+ if (init.headers instanceof Headers) init.headers.forEach((value, key) => {
111
+ headers.set(key, value);
112
+ });
113
+ else if (Array.isArray(init.headers)) {
114
+ for (const [key, value] of init.headers) if (value !== void 0) headers.set(key, String(value));
115
+ } else for (const [key, value] of Object.entries(init.headers)) if (value !== void 0) headers.set(key, String(value));
116
+ }
117
+ const incoming = (headers.get("anthropic-beta") || "").split(",").map((b) => b.trim()).filter(Boolean);
118
+ const required = ANTHROPIC_BETA_FLAGS.split(",");
119
+ const merged = [.../* @__PURE__ */ new Set([...required, ...incoming])].join(",");
120
+ headers.delete("authorization");
121
+ headers.delete("x-api-key");
122
+ headers.set("Authorization", `Bearer ${tokens.access}`);
123
+ headers.set("anthropic-beta", merged);
124
+ headers.set("user-agent", "claude-cli/2.1.2 (external, cli)");
125
+ let body = init?.body;
126
+ if (body && typeof body === "string") try {
127
+ const parsed = JSON.parse(body);
128
+ if (parsed.system && Array.isArray(parsed.system)) parsed.system = [{
129
+ type: "text",
130
+ text: SYSTEM_PREFIX
131
+ }, ...parsed.system];
132
+ else if (typeof parsed.system === "string") parsed.system = SYSTEM_PREFIX + "\n\n" + parsed.system;
133
+ else if (!parsed.system) parsed.system = [{
134
+ type: "text",
135
+ text: SYSTEM_PREFIX
136
+ }];
137
+ if (parsed.tools && Array.isArray(parsed.tools)) parsed.tools = parsed.tools.map((tool) => ({
138
+ ...tool,
139
+ name: prefixToolName(tool.name)
140
+ }));
141
+ if (parsed.messages && Array.isArray(parsed.messages)) parsed.messages = parsed.messages.map((msg) => {
142
+ if (msg.content && Array.isArray(msg.content)) msg.content = msg.content.map((block) => {
143
+ if (block.type === "tool_use" && block.name) return {
144
+ ...block,
145
+ name: prefixToolName(block.name)
146
+ };
147
+ return block;
148
+ });
149
+ return msg;
150
+ });
151
+ body = JSON.stringify(parsed);
152
+ } catch {}
153
+ let url;
154
+ if (typeof input === "string") url = input;
155
+ else if (input instanceof URL) url = input.toString();
156
+ else url = input.url;
157
+ try {
158
+ const parsed = new URL(url);
159
+ if (parsed.pathname === "/v1/messages" && !parsed.searchParams.has("beta")) {
160
+ parsed.searchParams.set("beta", "true");
161
+ url = parsed.toString();
162
+ }
163
+ } catch {}
164
+ const response = await globalThis.fetch(url, {
165
+ ...init,
166
+ body,
167
+ headers
168
+ });
169
+ if (!response.ok) {
170
+ const text = await response.text();
171
+ return new Response(text, {
172
+ status: response.status,
173
+ statusText: response.statusText,
174
+ headers: response.headers
175
+ });
176
+ }
177
+ if (response.body) {
178
+ if ((response.headers.get("content-type") ?? "").includes("application/json")) {
179
+ const rawText = await response.text();
180
+ const headers = new Headers(response.headers);
181
+ headers.delete("content-length");
182
+ headers.delete("content-encoding");
183
+ try {
184
+ const json = JSON.parse(rawText);
185
+ rewriteToolUseNames(json);
186
+ return new Response(JSON.stringify(json), {
187
+ status: response.status,
188
+ statusText: response.statusText,
189
+ headers
190
+ });
191
+ } catch {
192
+ return new Response(rawText, {
193
+ status: response.status,
194
+ statusText: response.statusText,
195
+ headers
196
+ });
197
+ }
198
+ }
199
+ const stream = response.body.pipeThrough(createAnthropicToolNameTransform());
200
+ return new Response(stream, {
201
+ status: response.status,
202
+ statusText: response.statusText,
203
+ headers: response.headers
204
+ });
205
+ }
206
+ return response;
207
+ };
231
208
  }
232
209
  function createAnthropicToolNameTransform() {
233
- const decoder = new TextDecoder();
234
- const encoder = new TextEncoder();
235
- let pending = "";
236
- return new TransformStream({
237
- transform(chunk, controller) {
238
- pending += decoder.decode(chunk, { stream: true });
239
- let newlineIndex = pending.indexOf("\n");
240
- while (newlineIndex !== -1) {
241
- const line = pending.slice(0, newlineIndex + 1);
242
- pending = pending.slice(newlineIndex + 1);
243
- controller.enqueue(encoder.encode(rewriteAnthropicEventLine(line)));
244
- newlineIndex = pending.indexOf("\n");
245
- }
246
- },
247
- flush(controller) {
248
- pending += decoder.decode();
249
- if (pending) {
250
- controller.enqueue(encoder.encode(rewriteAnthropicEventLine(pending)));
251
- pending = "";
252
- }
253
- }
254
- });
210
+ const decoder = new TextDecoder();
211
+ const encoder = new TextEncoder();
212
+ let pending = "";
213
+ return new TransformStream({
214
+ transform(chunk, controller) {
215
+ pending += decoder.decode(chunk, { stream: true });
216
+ let newlineIndex = pending.indexOf("\n");
217
+ while (newlineIndex !== -1) {
218
+ const line = pending.slice(0, newlineIndex + 1);
219
+ pending = pending.slice(newlineIndex + 1);
220
+ controller.enqueue(encoder.encode(rewriteAnthropicEventLine(line)));
221
+ newlineIndex = pending.indexOf("\n");
222
+ }
223
+ },
224
+ flush(controller) {
225
+ pending += decoder.decode();
226
+ if (pending) {
227
+ controller.enqueue(encoder.encode(rewriteAnthropicEventLine(pending)));
228
+ pending = "";
229
+ }
230
+ }
231
+ });
255
232
  }
256
233
  function rewriteAnthropicEventLine(line) {
257
- const match = /^(data:\s*)(.*?)(\r?\n?)$/.exec(line);
258
- if (!match) return line;
259
- const [, prefix, jsonText, suffix] = match;
260
- if (!jsonText || jsonText === "[DONE]") return line;
261
- try {
262
- const event = JSON.parse(jsonText);
263
- rewriteToolUseNames(event);
264
- return `${prefix}${JSON.stringify(event)}${suffix}`;
265
- } catch {
266
- return line;
267
- }
234
+ const match = /^(data:\s*)(.*?)(\r?\n?)$/.exec(line);
235
+ if (!match) return line;
236
+ const [, prefix, jsonText, suffix] = match;
237
+ if (!jsonText || jsonText === "[DONE]") return line;
238
+ try {
239
+ const event = JSON.parse(jsonText);
240
+ rewriteToolUseNames(event);
241
+ return `${prefix}${JSON.stringify(event)}${suffix}`;
242
+ } catch {
243
+ return line;
244
+ }
268
245
  }
269
246
  function rewriteToolUseNames(value) {
270
- if (!value || typeof value !== "object") return;
271
- if (Array.isArray(value)) {
272
- for (const item of value) rewriteToolUseNames(item);
273
- return;
274
- }
275
- const record = value;
276
- if (record.type === "tool_use") {
277
- record.name = stripToolNamePrefix(record.name);
278
- }
279
- for (const item of Object.values(record)) {
280
- rewriteToolUseNames(item);
281
- }
247
+ if (!value || typeof value !== "object") return;
248
+ if (Array.isArray(value)) {
249
+ for (const item of value) rewriteToolUseNames(item);
250
+ return;
251
+ }
252
+ const record = value;
253
+ if (record.type === "tool_use") record.name = stripToolNamePrefix(record.name);
254
+ for (const item of Object.values(record)) rewriteToolUseNames(item);
282
255
  }
283
-
284
256
  // src/openai-codex.ts
285
- import { createServer } from "http";
286
- import {
287
- createAuthFetch,
288
- generatePKCE as generatePKCE2,
289
- generateState
290
- } from "@vostride/agent-qa-core";
291
- var CODEX_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
292
- var CODEX_AUTH_BASE = "https://auth.openai.com";
293
- var CODEX_TOKEN_URL = "https://auth.openai.com/oauth/token";
294
- var CODEX_SCOPES = "openid profile email offline_access";
295
- var CODEX_API_URL = "https://chatgpt.com/backend-api/codex/responses";
296
- var CODEX_DEFAULT_PORT = 1455;
297
- var CODEX_CALLBACK_HOST = "localhost";
298
- var CODEX_LISTEN_HOST = "127.0.0.1";
257
+ const CODEX_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
258
+ const CODEX_AUTH_BASE = "https://auth.openai.com";
259
+ const CODEX_TOKEN_URL = "https://auth.openai.com/oauth/token";
260
+ const CODEX_SCOPES = "openid profile email offline_access";
261
+ const CODEX_API_URL = "https://chatgpt.com/backend-api/codex/responses";
262
+ const CODEX_DEFAULT_PORT = 1455;
263
+ const CODEX_CALLBACK_HOST = "localhost";
299
264
  function decodeJwtClaims(token) {
300
- const parts = token.split(".");
301
- if (parts.length < 3) throw new Error("Invalid JWT: expected 3 segments");
302
- const payload = parts[1];
303
- const decoded = Buffer.from(payload, "base64url").toString("utf-8");
304
- return JSON.parse(decoded);
265
+ const parts = token.split(".");
266
+ if (parts.length < 3) throw new Error("Invalid JWT: expected 3 segments");
267
+ const payload = parts[1];
268
+ const decoded = Buffer.from(payload, "base64url").toString("utf-8");
269
+ return JSON.parse(decoded);
305
270
  }
306
271
  function extractAccountId(idToken) {
307
- try {
308
- const claims = decodeJwtClaims(idToken);
309
- const authClaim = claims["https://api.openai.com/auth"];
310
- if (authClaim && typeof authClaim === "object") {
311
- const userIdStr = authClaim.user_id ?? authClaim.account_id;
312
- if (userIdStr) return userIdStr;
313
- }
314
- return claims.sub ?? void 0;
315
- } catch {
316
- return void 0;
317
- }
272
+ try {
273
+ const claims = decodeJwtClaims(idToken);
274
+ const authClaim = claims["https://api.openai.com/auth"];
275
+ if (authClaim && typeof authClaim === "object") {
276
+ const userIdStr = authClaim.user_id ?? authClaim.account_id;
277
+ if (userIdStr) return userIdStr;
278
+ }
279
+ return claims.sub ?? void 0;
280
+ } catch {
281
+ return;
282
+ }
318
283
  }
319
284
  async function codexExchangeCode(code, redirectUri, pkce) {
320
- const body = new URLSearchParams({
321
- grant_type: "authorization_code",
322
- client_id: CODEX_CLIENT_ID,
323
- code,
324
- redirect_uri: redirectUri,
325
- code_verifier: pkce.verifier
326
- });
327
- const res = await globalThis.fetch(CODEX_TOKEN_URL, {
328
- method: "POST",
329
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
330
- body: body.toString()
331
- });
332
- if (!res.ok) {
333
- const text = await res.text();
334
- throw new Error(`Codex token exchange failed: ${text}`);
335
- }
336
- const json = await res.json();
337
- if (typeof json.access_token !== "string" || typeof json.refresh_token !== "string" || typeof json.expires_in !== "number") {
338
- throw new Error("Codex token exchange response is missing required fields");
339
- }
340
- const accountId = typeof json.id_token === "string" ? extractAccountId(json.id_token) : void 0;
341
- return {
342
- access: json.access_token,
343
- refresh: json.refresh_token,
344
- expires: Date.now() + json.expires_in * 1e3,
345
- accountId
346
- };
285
+ const body = new URLSearchParams({
286
+ grant_type: "authorization_code",
287
+ client_id: CODEX_CLIENT_ID,
288
+ code,
289
+ redirect_uri: redirectUri,
290
+ code_verifier: pkce.verifier
291
+ });
292
+ const res = await globalThis.fetch(CODEX_TOKEN_URL, {
293
+ method: "POST",
294
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
295
+ body: body.toString()
296
+ });
297
+ if (!res.ok) {
298
+ const text = await res.text();
299
+ throw new Error(`Codex token exchange failed: ${text}`);
300
+ }
301
+ const json = await res.json();
302
+ if (typeof json.access_token !== "string" || typeof json.refresh_token !== "string" || typeof json.expires_in !== "number") throw new Error("Codex token exchange response is missing required fields");
303
+ const accountId = typeof json.id_token === "string" ? extractAccountId(json.id_token) : void 0;
304
+ return {
305
+ access: json.access_token,
306
+ refresh: json.refresh_token,
307
+ expires: Date.now() + json.expires_in * 1e3,
308
+ accountId
309
+ };
347
310
  }
348
- var codexRefreshTokens = async (_provider, refreshToken) => {
349
- const body = new URLSearchParams({
350
- grant_type: "refresh_token",
351
- client_id: CODEX_CLIENT_ID,
352
- refresh_token: refreshToken
353
- });
354
- const res = await globalThis.fetch(CODEX_TOKEN_URL, {
355
- method: "POST",
356
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
357
- body: body.toString()
358
- });
359
- if (!res.ok) {
360
- const text = await res.text();
361
- throw new Error(`Codex token refresh failed: ${text}`);
362
- }
363
- const json = await res.json();
364
- if (typeof json.access_token !== "string" || typeof json.expires_in !== "number") {
365
- throw new Error("Codex token refresh response is missing required fields");
366
- }
367
- const accountId = typeof json.id_token === "string" ? extractAccountId(json.id_token) : void 0;
368
- return {
369
- access: json.access_token,
370
- refresh: typeof json.refresh_token === "string" ? json.refresh_token : refreshToken,
371
- expires: Date.now() + json.expires_in * 1e3,
372
- accountId
373
- };
311
+ const codexRefreshTokens = async (_provider, refreshToken) => {
312
+ const body = new URLSearchParams({
313
+ grant_type: "refresh_token",
314
+ client_id: CODEX_CLIENT_ID,
315
+ refresh_token: refreshToken
316
+ });
317
+ const res = await globalThis.fetch(CODEX_TOKEN_URL, {
318
+ method: "POST",
319
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
320
+ body: body.toString()
321
+ });
322
+ if (!res.ok) {
323
+ const text = await res.text();
324
+ throw new Error(`Codex token refresh failed: ${text}`);
325
+ }
326
+ const json = await res.json();
327
+ if (typeof json.access_token !== "string" || typeof json.expires_in !== "number") throw new Error("Codex token refresh response is missing required fields");
328
+ const accountId = typeof json.id_token === "string" ? extractAccountId(json.id_token) : void 0;
329
+ return {
330
+ access: json.access_token,
331
+ refresh: typeof json.refresh_token === "string" ? json.refresh_token : refreshToken,
332
+ expires: Date.now() + json.expires_in * 1e3,
333
+ accountId
334
+ };
374
335
  };
375
336
  async function codexBrowserAuth(options) {
376
- const port = options?.port ?? CODEX_DEFAULT_PORT;
377
- const listenHost = options?.listenHost ?? CODEX_LISTEN_HOST;
378
- const redirectUri = `http://${CODEX_CALLBACK_HOST}:${port}/auth/callback`;
379
- const pkce = generatePKCE2();
380
- const state = generateState();
381
- let server;
382
- let resolveTokens;
383
- let rejectTokens;
384
- const waitForCallback = new Promise((resolve, reject) => {
385
- resolveTokens = resolve;
386
- rejectTokens = reject;
387
- });
388
- server = createServer(async (req, res) => {
389
- const url = new URL(req.url ?? "/", redirectUri);
390
- if (url.pathname === "/auth/callback") {
391
- const code = url.searchParams.get("code");
392
- const returnedState = url.searchParams.get("state");
393
- if (returnedState !== state) {
394
- res.writeHead(400, { "Content-Type": "text/html" });
395
- res.end("<html><body>State mismatch. Please try again.</body></html>");
396
- rejectTokens(new Error("OAuth state mismatch"));
397
- return;
398
- }
399
- if (!code) {
400
- res.writeHead(400, { "Content-Type": "text/html" });
401
- res.end("<html><body>Missing authorization code.</body></html>");
402
- rejectTokens(new Error("Missing authorization code"));
403
- return;
404
- }
405
- try {
406
- const tokens = await codexExchangeCode(code, redirectUri, {
407
- verifier: pkce.verifier
408
- });
409
- res.writeHead(200, { "Content-Type": "text/html" });
410
- res.end(
411
- "<html><body>Authentication successful! You can close this tab.</body></html>"
412
- );
413
- resolveTokens(tokens);
414
- } catch (err) {
415
- res.writeHead(500, { "Content-Type": "text/html" });
416
- res.end("<html><body>Token exchange failed.</body></html>");
417
- rejectTokens(
418
- err instanceof Error ? err : new Error("Token exchange failed")
419
- );
420
- }
421
- } else {
422
- res.writeHead(404);
423
- res.end();
424
- }
425
- });
426
- await new Promise((resolve, reject) => {
427
- server.once("error", reject);
428
- server.listen(port, listenHost, () => {
429
- server.off("error", reject);
430
- resolve();
431
- });
432
- });
433
- const params = new URLSearchParams({
434
- response_type: "code",
435
- client_id: CODEX_CLIENT_ID,
436
- redirect_uri: redirectUri,
437
- scope: CODEX_SCOPES,
438
- state,
439
- code_challenge: pkce.challenge,
440
- code_challenge_method: "S256"
441
- });
442
- const authorizeUrl = `${CODEX_AUTH_BASE}/oauth/authorize?${params.toString()}`;
443
- const cleanup = () => {
444
- server.close();
445
- };
446
- return { authorizeUrl, waitForCallback, cleanup };
337
+ const port = options?.port ?? 1455;
338
+ const listenHost = options?.listenHost ?? "127.0.0.1";
339
+ const redirectUri = `http://${CODEX_CALLBACK_HOST}:${port}/auth/callback`;
340
+ const pkce = generatePKCE();
341
+ const state = generateState();
342
+ let server;
343
+ let resolveTokens;
344
+ let rejectTokens;
345
+ const waitForCallback = new Promise((resolve, reject) => {
346
+ resolveTokens = resolve;
347
+ rejectTokens = reject;
348
+ });
349
+ server = createServer(async (req, res) => {
350
+ const url = new URL(req.url ?? "/", redirectUri);
351
+ if (url.pathname === "/auth/callback") {
352
+ const code = url.searchParams.get("code");
353
+ if (url.searchParams.get("state") !== state) {
354
+ res.writeHead(400, { "Content-Type": "text/html" });
355
+ res.end("<html><body>State mismatch. Please try again.</body></html>");
356
+ rejectTokens(/* @__PURE__ */ new Error("OAuth state mismatch"));
357
+ return;
358
+ }
359
+ if (!code) {
360
+ res.writeHead(400, { "Content-Type": "text/html" });
361
+ res.end("<html><body>Missing authorization code.</body></html>");
362
+ rejectTokens(/* @__PURE__ */ new Error("Missing authorization code"));
363
+ return;
364
+ }
365
+ try {
366
+ const tokens = await codexExchangeCode(code, redirectUri, { verifier: pkce.verifier });
367
+ res.writeHead(200, { "Content-Type": "text/html" });
368
+ res.end("<html><body>Authentication successful! You can close this tab.</body></html>");
369
+ resolveTokens(tokens);
370
+ } catch (err) {
371
+ res.writeHead(500, { "Content-Type": "text/html" });
372
+ res.end("<html><body>Token exchange failed.</body></html>");
373
+ rejectTokens(err instanceof Error ? err : /* @__PURE__ */ new Error("Token exchange failed"));
374
+ }
375
+ } else {
376
+ res.writeHead(404);
377
+ res.end();
378
+ }
379
+ });
380
+ await new Promise((resolve, reject) => {
381
+ server.once("error", reject);
382
+ server.listen(port, listenHost, () => {
383
+ server.off("error", reject);
384
+ resolve();
385
+ });
386
+ });
387
+ const params = new URLSearchParams({
388
+ response_type: "code",
389
+ client_id: CODEX_CLIENT_ID,
390
+ redirect_uri: redirectUri,
391
+ scope: CODEX_SCOPES,
392
+ state,
393
+ code_challenge: pkce.challenge,
394
+ code_challenge_method: "S256"
395
+ });
396
+ const authorizeUrl = `${CODEX_AUTH_BASE}/oauth/authorize?${params.toString()}`;
397
+ const cleanup = () => {
398
+ server.close();
399
+ };
400
+ return {
401
+ authorizeUrl,
402
+ waitForCallback,
403
+ cleanup
404
+ };
447
405
  }
448
406
  function createCodexAuthFetch(getTokens, onRefreshed) {
449
- const authFetch = createAuthFetch({
450
- provider: "openai-codex",
451
- getTokens,
452
- refreshTokens: codexRefreshTokens,
453
- onTokensRefreshed: onRefreshed,
454
- headerTransform: (headers, tokens) => {
455
- if (tokens.accountId) {
456
- headers.set("ChatGPT-Account-Id", tokens.accountId);
457
- }
458
- },
459
- urlTransform: (url) => {
460
- if (url.includes("/v1/responses") || url.includes("/chat/completions")) {
461
- return CODEX_API_URL;
462
- }
463
- return url;
464
- }
465
- });
466
- return async (input, init) => {
467
- const inputUrl = extractRequestUrl(input);
468
- let forceStream = false;
469
- let body = init?.body;
470
- if (isCodexRequestUrl(inputUrl) && body && typeof body === "string") {
471
- try {
472
- const parsed = JSON.parse(body);
473
- if (!parsed.stream) {
474
- parsed.stream = true;
475
- forceStream = true;
476
- }
477
- if (parsed.text?.format?.strict) {
478
- parsed.text.format.strict = false;
479
- }
480
- body = JSON.stringify(parsed);
481
- } catch {
482
- }
483
- }
484
- const response = await authFetch(input, { ...init, body });
485
- if (forceStream && response.ok && response.body) {
486
- return bufferCodexSSEResponse(response);
487
- }
488
- return response;
489
- };
407
+ const authFetch = createAuthFetch({
408
+ provider: "openai-codex",
409
+ getTokens,
410
+ refreshTokens: codexRefreshTokens,
411
+ onTokensRefreshed: onRefreshed,
412
+ headerTransform: (headers, tokens) => {
413
+ if (tokens.accountId) headers.set("ChatGPT-Account-Id", tokens.accountId);
414
+ },
415
+ urlTransform: (url) => {
416
+ if (url.includes("/v1/responses") || url.includes("/chat/completions")) return CODEX_API_URL;
417
+ return url;
418
+ }
419
+ });
420
+ return async (input, init) => {
421
+ const inputUrl = extractRequestUrl(input);
422
+ let forceStream = false;
423
+ let body = init?.body;
424
+ if (isCodexRequestUrl(inputUrl) && body && typeof body === "string") try {
425
+ const parsed = JSON.parse(body);
426
+ if (!parsed.stream) {
427
+ parsed.stream = true;
428
+ forceStream = true;
429
+ }
430
+ if (parsed.text?.format?.strict) parsed.text.format.strict = false;
431
+ body = JSON.stringify(parsed);
432
+ } catch {}
433
+ const response = await authFetch(input, {
434
+ ...init,
435
+ body
436
+ });
437
+ if (forceStream && response.ok && response.body) return bufferCodexSSEResponse(response);
438
+ return response;
439
+ };
490
440
  }
491
441
  function extractRequestUrl(input) {
492
- if (typeof input === "string") return input;
493
- if (input instanceof URL) return input.toString();
494
- return input.url;
442
+ if (typeof input === "string") return input;
443
+ if (input instanceof URL) return input.toString();
444
+ return input.url;
495
445
  }
496
446
  function isCodexRequestUrl(url) {
497
- return url.includes("/v1/responses") || url.includes("/chat/completions") || url.includes("chatgpt.com/backend-api/codex");
447
+ return url.includes("/v1/responses") || url.includes("/chat/completions") || url.includes("chatgpt.com/backend-api/codex");
498
448
  }
499
449
  async function bufferCodexSSEResponse(response) {
500
- const reader = response.body.getReader();
501
- const decoder = new TextDecoder();
502
- let buffer = "";
503
- let completedResponse = null;
504
- let outputText = "";
505
- const pendingOutputItems = /* @__PURE__ */ new Map();
506
- const completedOutputItems = /* @__PURE__ */ new Map();
507
- const functionCallArgumentDeltas = /* @__PURE__ */ new Map();
508
- const customToolInputDeltas = /* @__PURE__ */ new Map();
509
- const overallTimeout = setTimeout(() => {
510
- try {
511
- reader.cancel();
512
- } catch {
513
- }
514
- }, 12e4);
515
- try {
516
- while (true) {
517
- const chunkPromise = reader.read();
518
- const timeoutPromise = new Promise(
519
- (resolve) => setTimeout(() => resolve({ done: true, value: void 0 }), 3e4)
520
- );
521
- const { done, value } = await Promise.race([chunkPromise, timeoutPromise]);
522
- if (done) break;
523
- buffer += decoder.decode(value, { stream: true });
524
- const lines = buffer.split("\n");
525
- buffer = lines.pop() ?? "";
526
- for (const line of lines) {
527
- if (!line.startsWith("data: ")) continue;
528
- const data = line.slice(6).trim();
529
- if (data === "[DONE]") continue;
530
- try {
531
- const event = JSON.parse(data);
532
- if (!isJSONRecord(event) || typeof event.type !== "string") continue;
533
- if (event.type === "response.output_text.delta" && typeof event.delta === "string") {
534
- outputText += event.delta;
535
- }
536
- if (event.type === "response.output_item.added" && typeof event.output_index === "number" && isJSONRecord(event.item)) {
537
- pendingOutputItems.set(event.output_index, { ...event.item });
538
- }
539
- if (event.type === "response.function_call_arguments.delta" && typeof event.output_index === "number" && typeof event.delta === "string") {
540
- const prev = functionCallArgumentDeltas.get(event.output_index) ?? "";
541
- functionCallArgumentDeltas.set(event.output_index, prev + event.delta);
542
- }
543
- if (event.type === "response.custom_tool_call_input.delta" && typeof event.output_index === "number" && typeof event.delta === "string") {
544
- const prev = customToolInputDeltas.get(event.output_index) ?? "";
545
- customToolInputDeltas.set(event.output_index, prev + event.delta);
546
- }
547
- if (event.type === "response.output_item.done" && typeof event.output_index === "number" && isJSONRecord(event.item)) {
548
- completedOutputItems.set(
549
- event.output_index,
550
- hydrateOutputItem(event.item, event.output_index, functionCallArgumentDeltas, customToolInputDeltas)
551
- );
552
- }
553
- if ((event.type === "response.completed" || event.type === "response.incomplete") && isJSONRecord(event.response)) {
554
- completedResponse = event.response;
555
- }
556
- } catch {
557
- }
558
- }
559
- }
560
- } finally {
561
- clearTimeout(overallTimeout);
562
- }
563
- for (const [outputIndex, item] of pendingOutputItems) {
564
- if (!completedOutputItems.has(outputIndex)) {
565
- completedOutputItems.set(
566
- outputIndex,
567
- hydrateOutputItem(item, outputIndex, functionCallArgumentDeltas, customToolInputDeltas)
568
- );
569
- }
570
- }
571
- const bufferedOutput = [...completedOutputItems.entries()].sort(([left], [right]) => left - right).map(([, item]) => item);
572
- const body = JSON.stringify(
573
- ensureResponseMetadata(
574
- completedResponse ? mergeBufferedOutputItems(completedResponse, bufferedOutput, outputText) : createBufferedResponse(bufferedOutput, outputText)
575
- )
576
- );
577
- return new Response(body, {
578
- status: 200,
579
- headers: { "content-type": "application/json" }
580
- });
450
+ const reader = response.body.getReader();
451
+ const decoder = new TextDecoder();
452
+ let buffer = "";
453
+ let completedResponse = null;
454
+ let outputText = "";
455
+ const pendingOutputItems = /* @__PURE__ */ new Map();
456
+ const completedOutputItems = /* @__PURE__ */ new Map();
457
+ const functionCallArgumentDeltas = /* @__PURE__ */ new Map();
458
+ const customToolInputDeltas = /* @__PURE__ */ new Map();
459
+ const overallTimeout = setTimeout(() => {
460
+ try {
461
+ reader.cancel();
462
+ } catch {}
463
+ }, 12e4);
464
+ try {
465
+ while (true) {
466
+ const chunkPromise = reader.read();
467
+ const timeoutPromise = new Promise((resolve) => setTimeout(() => resolve({
468
+ done: true,
469
+ value: void 0
470
+ }), 3e4));
471
+ const { done, value } = await Promise.race([chunkPromise, timeoutPromise]);
472
+ if (done) break;
473
+ buffer += decoder.decode(value, { stream: true });
474
+ const lines = buffer.split("\n");
475
+ buffer = lines.pop() ?? "";
476
+ for (const line of lines) {
477
+ if (!line.startsWith("data: ")) continue;
478
+ const data = line.slice(6).trim();
479
+ if (data === "[DONE]") continue;
480
+ try {
481
+ const event = JSON.parse(data);
482
+ if (!isJSONRecord(event) || typeof event.type !== "string") continue;
483
+ if (event.type === "response.output_text.delta" && typeof event.delta === "string") outputText += event.delta;
484
+ if (event.type === "response.output_item.added" && typeof event.output_index === "number" && isJSONRecord(event.item)) pendingOutputItems.set(event.output_index, { ...event.item });
485
+ if (event.type === "response.function_call_arguments.delta" && typeof event.output_index === "number" && typeof event.delta === "string") {
486
+ const prev = functionCallArgumentDeltas.get(event.output_index) ?? "";
487
+ functionCallArgumentDeltas.set(event.output_index, prev + event.delta);
488
+ }
489
+ if (event.type === "response.custom_tool_call_input.delta" && typeof event.output_index === "number" && typeof event.delta === "string") {
490
+ const prev = customToolInputDeltas.get(event.output_index) ?? "";
491
+ customToolInputDeltas.set(event.output_index, prev + event.delta);
492
+ }
493
+ if (event.type === "response.output_item.done" && typeof event.output_index === "number" && isJSONRecord(event.item)) completedOutputItems.set(event.output_index, hydrateOutputItem(event.item, event.output_index, functionCallArgumentDeltas, customToolInputDeltas));
494
+ if ((event.type === "response.completed" || event.type === "response.incomplete") && isJSONRecord(event.response)) completedResponse = event.response;
495
+ } catch {}
496
+ }
497
+ }
498
+ } finally {
499
+ clearTimeout(overallTimeout);
500
+ }
501
+ for (const [outputIndex, item] of pendingOutputItems) if (!completedOutputItems.has(outputIndex)) completedOutputItems.set(outputIndex, hydrateOutputItem(item, outputIndex, functionCallArgumentDeltas, customToolInputDeltas));
502
+ const bufferedOutput = [...completedOutputItems.entries()].sort(([left], [right]) => left - right).map(([, item]) => item);
503
+ const body = JSON.stringify(ensureResponseMetadata(completedResponse ? mergeBufferedOutputItems(completedResponse, bufferedOutput, outputText) : createBufferedResponse(bufferedOutput, outputText)));
504
+ return new Response(body, {
505
+ status: 200,
506
+ headers: { "content-type": "application/json" }
507
+ });
581
508
  }
582
509
  function isJSONRecord(value) {
583
- return value !== null && typeof value === "object" && !Array.isArray(value);
510
+ return value !== null && typeof value === "object" && !Array.isArray(value);
584
511
  }
585
512
  function hydrateOutputItem(item, outputIndex, functionCallArgumentDeltas, customToolInputDeltas) {
586
- const hydrated = { ...item };
587
- if (hydrated.type === "function_call" && typeof hydrated.arguments !== "string") {
588
- hydrated.arguments = functionCallArgumentDeltas.get(outputIndex) ?? "";
589
- }
590
- if (hydrated.type === "custom_tool_call" && hydrated.input == null) {
591
- const input = customToolInputDeltas.get(outputIndex);
592
- if (input !== void 0) {
593
- hydrated.input = safeParseJSON(input) ?? input;
594
- }
595
- }
596
- return hydrated;
513
+ const hydrated = { ...item };
514
+ if (hydrated.type === "function_call" && typeof hydrated.arguments !== "string") hydrated.arguments = functionCallArgumentDeltas.get(outputIndex) ?? "";
515
+ if (hydrated.type === "custom_tool_call" && hydrated.input == null) {
516
+ const input = customToolInputDeltas.get(outputIndex);
517
+ if (input !== void 0) hydrated.input = safeParseJSON(input) ?? input;
518
+ }
519
+ return hydrated;
597
520
  }
598
521
  function mergeBufferedOutputItems(response, bufferedOutput, outputText) {
599
- const existingOutput = Array.isArray(response.output) ? response.output.filter(isJSONRecord) : [];
600
- if (bufferedOutput.length === 0) {
601
- if (existingOutput.length > 0) return response;
602
- return { ...response, output: [buildTextOutput(outputText)] };
603
- }
604
- const mergedOutput = [...existingOutput];
605
- const seenKeys = new Set(existingOutput.map(getOutputItemKey).filter((key) => key !== null));
606
- for (const item of bufferedOutput) {
607
- const key = getOutputItemKey(item);
608
- if (key && seenKeys.has(key)) continue;
609
- if (key) seenKeys.add(key);
610
- mergedOutput.push(item);
611
- }
612
- return { ...response, output: mergedOutput };
522
+ const existingOutput = Array.isArray(response.output) ? response.output.filter(isJSONRecord) : [];
523
+ if (bufferedOutput.length === 0) {
524
+ if (existingOutput.length > 0) return response;
525
+ return {
526
+ ...response,
527
+ output: [buildTextOutput(outputText)]
528
+ };
529
+ }
530
+ const mergedOutput = [...existingOutput];
531
+ const seenKeys = new Set(existingOutput.map(getOutputItemKey).filter((key) => key !== null));
532
+ for (const item of bufferedOutput) {
533
+ const key = getOutputItemKey(item);
534
+ if (key && seenKeys.has(key)) continue;
535
+ if (key) seenKeys.add(key);
536
+ mergedOutput.push(item);
537
+ }
538
+ return {
539
+ ...response,
540
+ output: mergedOutput
541
+ };
613
542
  }
614
543
  function createBufferedResponse(bufferedOutput, outputText) {
615
- return {
616
- id: "codex-buffered",
617
- output: bufferedOutput.length > 0 ? bufferedOutput : [buildTextOutput(outputText)],
618
- status: "completed"
619
- };
544
+ return {
545
+ id: "codex-buffered",
546
+ output: bufferedOutput.length > 0 ? bufferedOutput : [buildTextOutput(outputText)],
547
+ status: "completed"
548
+ };
620
549
  }
621
550
  function ensureResponseMetadata(response) {
622
- if (typeof response.created_at === "number") return response;
623
- return {
624
- ...response,
625
- created_at: Math.floor(Date.now() / 1e3)
626
- };
551
+ if (typeof response.created_at === "number") return response;
552
+ return {
553
+ ...response,
554
+ created_at: Math.floor(Date.now() / 1e3)
555
+ };
627
556
  }
628
557
  function buildTextOutput(outputText) {
629
- return {
630
- type: "message",
631
- role: "assistant",
632
- content: [{ type: "output_text", text: outputText, annotations: [] }]
633
- };
558
+ return {
559
+ type: "message",
560
+ role: "assistant",
561
+ content: [{
562
+ type: "output_text",
563
+ text: outputText,
564
+ annotations: []
565
+ }]
566
+ };
634
567
  }
635
568
  function getOutputItemKey(item) {
636
- const type = typeof item.type === "string" ? item.type : "unknown";
637
- if (typeof item.id === "string") return `${type}:${item.id}`;
638
- if (typeof item.call_id === "string") return `${type}:${item.call_id}`;
639
- return null;
569
+ const type = typeof item.type === "string" ? item.type : "unknown";
570
+ if (typeof item.id === "string") return `${type}:${item.id}`;
571
+ if (typeof item.call_id === "string") return `${type}:${item.call_id}`;
572
+ return null;
640
573
  }
641
574
  function safeParseJSON(text) {
642
- try {
643
- return JSON.parse(text);
644
- } catch {
645
- return void 0;
646
- }
575
+ try {
576
+ return JSON.parse(text);
577
+ } catch {
578
+ return;
579
+ }
647
580
  }
648
-
649
581
  // src/index.ts
650
582
  function createSubscriptionAuthPlugin() {
651
- return {
652
- providers: [
653
- {
654
- providerId: "openai-subscription",
655
- credentialProviderId: "openai-subscription-oauth",
656
- label: "OpenAI subscription",
657
- modelAdapter: "openai-responses",
658
- dashboardAuth: { mode: "browser-poll", buttonLabel: "Login with OpenAI subscription" },
659
- async startAuth() {
660
- const result = await codexBrowserAuth();
661
- return {
662
- authorizeUrl: result.authorizeUrl,
663
- waitForTokens: result.waitForCallback,
664
- cleanup: result.cleanup
665
- };
666
- },
667
- createAuthFetch({ getTokens, onRefreshed }) {
668
- return createCodexAuthFetch(getTokens, onRefreshed);
669
- }
670
- },
671
- {
672
- providerId: "anthropic-subscription",
673
- credentialProviderId: "anthropic-subscription",
674
- label: "Anthropic subscription",
675
- modelAdapter: "anthropic-messages",
676
- dashboardAuth: { mode: "manual-code", buttonLabel: "Login with Anthropic subscription" },
677
- async startAuth() {
678
- return startAnthropicAuth();
679
- },
680
- async exchangeCode(ctx) {
681
- return await exchangeAnthropicManualCode(ctx);
682
- },
683
- createAuthFetch({ getTokens, onRefreshed }) {
684
- return createAnthropicAuthFetch(getTokens, onRefreshed);
685
- }
686
- }
687
- ]
688
- };
583
+ return { providers: [{
584
+ providerId: "openai-subscription",
585
+ credentialProviderId: "openai-subscription-oauth",
586
+ label: "OpenAI subscription",
587
+ modelAdapter: "openai-responses",
588
+ dashboardAuth: {
589
+ mode: "browser-poll",
590
+ buttonLabel: "Login with OpenAI subscription"
591
+ },
592
+ async startAuth() {
593
+ const result = await codexBrowserAuth();
594
+ return {
595
+ authorizeUrl: result.authorizeUrl,
596
+ waitForTokens: result.waitForCallback,
597
+ cleanup: result.cleanup
598
+ };
599
+ },
600
+ createAuthFetch({ getTokens, onRefreshed }) {
601
+ return createCodexAuthFetch(getTokens, onRefreshed);
602
+ }
603
+ }, {
604
+ providerId: "anthropic-subscription",
605
+ credentialProviderId: "anthropic-subscription",
606
+ label: "Anthropic subscription",
607
+ modelAdapter: "anthropic-messages",
608
+ dashboardAuth: {
609
+ mode: "manual-code",
610
+ buttonLabel: "Login with Anthropic subscription"
611
+ },
612
+ async startAuth() {
613
+ return startAnthropicAuth();
614
+ },
615
+ async exchangeCode(ctx) {
616
+ return await exchangeAnthropicManualCode(ctx);
617
+ },
618
+ createAuthFetch({ getTokens, onRefreshed }) {
619
+ return createAnthropicAuthFetch(getTokens, onRefreshed);
620
+ }
621
+ }] };
689
622
  }
690
- var index_default = createSubscriptionAuthPlugin;
691
- export {
692
- ANTHROPIC_BETA_FLAGS,
693
- ANTHROPIC_CLIENT_ID,
694
- ANTHROPIC_REDIRECT_URI,
695
- ANTHROPIC_SCOPES,
696
- ANTHROPIC_TOKEN_URL,
697
- CODEX_API_URL,
698
- CODEX_AUTH_BASE,
699
- CODEX_CLIENT_ID,
700
- CODEX_DEFAULT_PORT,
701
- CODEX_SCOPES,
702
- CODEX_TOKEN_URL,
703
- anthropicAuthorizeUrl,
704
- anthropicExchangeCode,
705
- anthropicRefreshTokens,
706
- codexBrowserAuth,
707
- codexExchangeCode,
708
- codexRefreshTokens,
709
- createAnthropicAuthFetch,
710
- createCodexAuthFetch,
711
- createSubscriptionAuthPlugin,
712
- decodeJwtClaims,
713
- index_default as default
714
- };
623
+ export { ANTHROPIC_BETA_FLAGS, ANTHROPIC_CLIENT_ID, ANTHROPIC_REDIRECT_URI, ANTHROPIC_SCOPES, ANTHROPIC_TOKEN_URL, CODEX_API_URL, CODEX_AUTH_BASE, CODEX_CLIENT_ID, CODEX_DEFAULT_PORT, CODEX_SCOPES, CODEX_TOKEN_URL, anthropicAuthorizeUrl, anthropicExchangeCode, anthropicRefreshTokens, codexBrowserAuth, codexExchangeCode, codexRefreshTokens, createAnthropicAuthFetch, createCodexAuthFetch, createSubscriptionAuthPlugin, createSubscriptionAuthPlugin as default, decodeJwtClaims };
624
+
715
625
  //# sourceMappingURL=index.js.map