openai-codex-oauth 0.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,25 +1,605 @@
1
- import {
2
- DEFAULT_CLIENT_ID,
3
- DEFAULT_CODEX_BASE_URL,
4
- DEFAULT_ISSUER,
5
- OpenAIOAuthError,
6
- createCodexOAuthClient,
7
- createCodexOAuthFetch,
8
- createMemoryTokenStore,
9
- createOpenAIOAuthProxy,
10
- normalizeCodexResponsesBody,
11
- refreshOpenAITokens,
12
- startOpenAIDeviceFlow
13
- } from "./chunk-DXYYRLYI.js";
14
- import {
15
- deriveAccountId,
16
- deriveExpiresAt,
17
- parseJwtClaims
18
- } from "./chunk-SCKIRN2D.js";
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ DEFAULT_CLIENT_ID: () => DEFAULT_CLIENT_ID,
24
+ DEFAULT_CODEX_BASE_URL: () => DEFAULT_CODEX_BASE_URL,
25
+ DEFAULT_ISSUER: () => DEFAULT_ISSUER,
26
+ OpenAIOAuthError: () => OpenAIOAuthError,
27
+ createCodexOAuthClient: () => createCodexOAuthClient,
28
+ createCodexOAuthFetch: () => createCodexOAuthFetch,
29
+ createMemoryTokenStore: () => createMemoryTokenStore,
30
+ createOpenAIOAuth: () => createOpenAIOAuth,
31
+ createOpenAIOAuthProxy: () => createOpenAIOAuthProxy,
32
+ deriveAccountId: () => deriveAccountId,
33
+ deriveExpiresAt: () => deriveExpiresAt,
34
+ normalizeCodexResponsesBody: () => normalizeCodexResponsesBody,
35
+ parseJwtClaims: () => parseJwtClaims,
36
+ refreshOpenAITokens: () => refreshOpenAITokens,
37
+ startOpenAIDeviceFlow: () => startOpenAIDeviceFlow
38
+ });
39
+ module.exports = __toCommonJS(index_exports);
40
+
41
+ // src/jwt.ts
42
+ function decodeBase64Url(value) {
43
+ try {
44
+ const base64 = value.replace(/-/g, "+").replace(/_/g, "/");
45
+ const padded = base64 + "=".repeat((4 - base64.length % 4) % 4);
46
+ if (typeof globalThis.atob === "function") {
47
+ const binary = globalThis.atob(padded);
48
+ const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));
49
+ return new TextDecoder().decode(bytes);
50
+ }
51
+ return Buffer.from(padded, "base64").toString("utf8");
52
+ } catch {
53
+ return void 0;
54
+ }
55
+ }
56
+ function isRecord(value) {
57
+ return typeof value === "object" && value !== null && !Array.isArray(value);
58
+ }
59
+ function parseJwtClaims(token) {
60
+ if (!token?.includes(".")) {
61
+ return void 0;
62
+ }
63
+ const parts = token.split(".");
64
+ if (parts.length !== 3 || !parts[1]) {
65
+ return void 0;
66
+ }
67
+ const payload = decodeBase64Url(parts[1]);
68
+ if (!payload) {
69
+ return void 0;
70
+ }
71
+ try {
72
+ const parsed = JSON.parse(payload);
73
+ return isRecord(parsed) ? parsed : void 0;
74
+ } catch {
75
+ return void 0;
76
+ }
77
+ }
78
+ function deriveAccountId(...tokens) {
79
+ for (const token of tokens) {
80
+ const claims = parseJwtClaims(token);
81
+ const auth = claims?.["https://api.openai.com/auth"];
82
+ if (isRecord(auth) && typeof auth.chatgpt_account_id === "string" && auth.chatgpt_account_id.length > 0) {
83
+ return auth.chatgpt_account_id;
84
+ }
85
+ }
86
+ return void 0;
87
+ }
88
+ function deriveExpiresAt(token) {
89
+ const claims = parseJwtClaims(token);
90
+ return typeof claims?.exp === "number" ? claims.exp * 1e3 : void 0;
91
+ }
92
+
93
+ // src/types.ts
94
+ var OpenAIOAuthError = class extends Error {
95
+ code;
96
+ constructor(code, message, options) {
97
+ super(message, options);
98
+ this.name = "OpenAIOAuthError";
99
+ this.code = code;
100
+ }
101
+ };
102
+
103
+ // src/device-flow.ts
104
+ var DEFAULT_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
105
+ var DEFAULT_ISSUER = "https://auth.openai.com";
106
+ var POLL_BUFFER_MS = 3e3;
107
+ function pickFetch(customFetch) {
108
+ if (typeof customFetch === "function") {
109
+ return customFetch;
110
+ }
111
+ if (typeof globalThis.fetch === "function") {
112
+ return globalThis.fetch.bind(globalThis);
113
+ }
114
+ throw new OpenAIOAuthError("fetch_required", "A fetch implementation is required for OpenAI OAuth.");
115
+ }
116
+ async function startOpenAIDeviceFlow(options = {}) {
117
+ const fetch = pickFetch(options.fetch);
118
+ const issuer = (options.issuer ?? DEFAULT_ISSUER).replace(/\/$/, "");
119
+ const clientId = options.clientId ?? DEFAULT_CLIENT_ID;
120
+ const now = options.now ?? (() => Date.now());
121
+ const sleep = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
122
+ const codeResponse = await fetch(`${issuer}/api/accounts/deviceauth/usercode`, {
123
+ method: "POST",
124
+ headers: {
125
+ "Content-Type": "application/json"
126
+ },
127
+ body: JSON.stringify({ client_id: clientId })
128
+ });
129
+ if (!codeResponse.ok) {
130
+ throw new OpenAIOAuthError("auth_failed", "Failed to initiate OpenAI authorization.");
131
+ }
132
+ const device = await codeResponse.json();
133
+ if (!device.device_auth_id || !device.user_code) {
134
+ throw new OpenAIOAuthError("auth_failed", "OpenAI authorization response did not include a device code.");
135
+ }
136
+ const intervalSeconds = typeof device.interval === "number" ? device.interval : parseInt(device.interval ?? "5", 10);
137
+ const intervalMs = Math.max(Number.isFinite(intervalSeconds) ? intervalSeconds : 5, 1) * 1e3;
138
+ return {
139
+ providerId: "openai",
140
+ url: `${issuer}/codex/device`,
141
+ code: device.user_code,
142
+ instructions: `Enter code: ${device.user_code}`,
143
+ async complete() {
144
+ while (true) {
145
+ const poll = await fetch(`${issuer}/api/accounts/deviceauth/token`, {
146
+ method: "POST",
147
+ headers: {
148
+ "Content-Type": "application/json"
149
+ },
150
+ body: JSON.stringify({
151
+ device_auth_id: device.device_auth_id,
152
+ user_code: device.user_code
153
+ })
154
+ });
155
+ if (poll.ok) {
156
+ const grant = await poll.json();
157
+ if (!grant.authorization_code || !grant.code_verifier) {
158
+ throw new OpenAIOAuthError("auth_failed", "OpenAI authorization grant was incomplete.");
159
+ }
160
+ const tokens = await exchangeAuthorizationCode({
161
+ fetch,
162
+ issuer,
163
+ clientId,
164
+ authorizationCode: grant.authorization_code,
165
+ codeVerifier: grant.code_verifier,
166
+ now
167
+ });
168
+ await options.tokenStore?.save(tokens);
169
+ return tokens;
170
+ }
171
+ if (poll.status !== 403 && poll.status !== 404) {
172
+ throw new OpenAIOAuthError("auth_failed", "OpenAI OAuth authorization failed.");
173
+ }
174
+ await sleep(intervalMs + POLL_BUFFER_MS);
175
+ }
176
+ }
177
+ };
178
+ }
179
+ async function exchangeAuthorizationCode({
180
+ fetch,
181
+ issuer,
182
+ clientId,
183
+ authorizationCode,
184
+ codeVerifier,
185
+ now
186
+ }) {
187
+ const response = await fetch(`${issuer}/oauth/token`, {
188
+ method: "POST",
189
+ headers: {
190
+ "Content-Type": "application/x-www-form-urlencoded"
191
+ },
192
+ body: new URLSearchParams({
193
+ grant_type: "authorization_code",
194
+ code: authorizationCode,
195
+ redirect_uri: `${issuer}/deviceauth/callback`,
196
+ client_id: clientId,
197
+ code_verifier: codeVerifier
198
+ }).toString()
199
+ });
200
+ if (!response.ok) {
201
+ throw new OpenAIOAuthError("auth_failed", "OpenAI token exchange failed.");
202
+ }
203
+ const token = await response.json();
204
+ if (!token.access_token) {
205
+ throw new OpenAIOAuthError("auth_failed", "OpenAI token exchange did not return an access token.");
206
+ }
207
+ return {
208
+ refreshToken: token.refresh_token,
209
+ accessToken: token.access_token,
210
+ idToken: token.id_token,
211
+ expiresAt: now() + (token.expires_in ?? 3600) * 1e3,
212
+ accountId: deriveAccountId(token.id_token, token.access_token)
213
+ };
214
+ }
215
+ async function refreshOpenAITokens({
216
+ tokens,
217
+ fetch,
218
+ clientId = DEFAULT_CLIENT_ID,
219
+ issuer = DEFAULT_ISSUER,
220
+ tokenUrl,
221
+ now = () => Date.now()
222
+ }) {
223
+ if (!tokens.refreshToken) {
224
+ return void 0;
225
+ }
226
+ const resolvedIssuer = issuer.replace(/\/$/, "");
227
+ const response = await fetch(tokenUrl ?? `${resolvedIssuer}/oauth/token`, {
228
+ method: "POST",
229
+ headers: {
230
+ "Content-Type": "application/x-www-form-urlencoded"
231
+ },
232
+ body: new URLSearchParams({
233
+ grant_type: "refresh_token",
234
+ refresh_token: tokens.refreshToken,
235
+ client_id: clientId,
236
+ scope: "openid profile email offline_access"
237
+ }).toString()
238
+ });
239
+ if (!response.ok) {
240
+ return void 0;
241
+ }
242
+ const payload = await response.json();
243
+ if (!payload.access_token) {
244
+ return void 0;
245
+ }
246
+ const next = {
247
+ accessToken: payload.access_token,
248
+ refreshToken: payload.refresh_token ?? tokens.refreshToken,
249
+ idToken: payload.id_token ?? tokens.idToken,
250
+ expiresAt: now() + (payload.expires_in ?? 3600) * 1e3
251
+ };
252
+ next.accountId = deriveAccountId(next.idToken, next.accessToken) ?? tokens.accountId;
253
+ return next;
254
+ }
255
+
256
+ // src/memory-token-store.ts
257
+ function createMemoryTokenStore(initial) {
258
+ let current = initial;
259
+ return {
260
+ async load() {
261
+ return current;
262
+ },
263
+ async save(tokens) {
264
+ current = tokens;
265
+ }
266
+ };
267
+ }
268
+
269
+ // src/codex-fetch.ts
270
+ var DEFAULT_CODEX_BASE_URL = "https://chatgpt.com/backend-api/codex";
271
+ var DEFAULT_BROWSER_PROXY_BASE_URL = "/api/proxy/openai/codex";
272
+ var DEFAULT_REFRESH_MARGIN_MS = 5 * 60 * 1e3;
273
+ var DEFAULT_INSTRUCTIONS = "";
274
+ var DEFAULT_ORIGINATOR = "openai-codex-oauth";
275
+ function pickFetch2(customFetch) {
276
+ if (typeof customFetch === "function") {
277
+ return customFetch;
278
+ }
279
+ if (typeof globalThis.fetch === "function") {
280
+ return globalThis.fetch.bind(globalThis);
281
+ }
282
+ throw new OpenAIOAuthError("fetch_required", "A fetch implementation is required for OpenAI OAuth.");
283
+ }
284
+ function withoutTrailingSlash(value) {
285
+ return value.replace(/\/$/, "");
286
+ }
287
+ function resolveBaseURL(baseURL) {
288
+ return withoutTrailingSlash(baseURL ?? DEFAULT_CODEX_BASE_URL);
289
+ }
290
+ function createStore(settings) {
291
+ if (settings.tokenStore) {
292
+ return settings.tokenStore;
293
+ }
294
+ if (settings.tokens) {
295
+ return createMemoryTokenStore(settings.tokens);
296
+ }
297
+ throw new OpenAIOAuthError(
298
+ "tokens_required",
299
+ "OpenAI OAuth tokens are required. Pass `tokens`, `tokenStore`, or use `createCodexAuthFileStore` from `@tolksyn/openai-oauth/node`."
300
+ );
301
+ }
302
+ function needsRefresh(tokens, now, marginMs) {
303
+ const expiresAt = tokens.expiresAt ?? deriveExpiresAt(tokens.accessToken);
304
+ if (!tokens.accessToken) {
305
+ return true;
306
+ }
307
+ if (expiresAt == null || expiresAt <= 0) {
308
+ return false;
309
+ }
310
+ return expiresAt <= now + marginMs;
311
+ }
312
+ function hasExpired(tokens, now) {
313
+ const expiresAt = tokens.expiresAt ?? deriveExpiresAt(tokens.accessToken);
314
+ return expiresAt != null && expiresAt > 0 && expiresAt <= now;
315
+ }
316
+ var TokenManager = class {
317
+ constructor(settings, store, fetch) {
318
+ this.settings = settings;
319
+ this.store = store;
320
+ this.fetch = fetch;
321
+ }
322
+ settings;
323
+ store;
324
+ fetch;
325
+ /** Promise for an in-flight token refresh to coalesce concurrent requests. */
326
+ inflight;
327
+ /** Cached current tokens to avoid redundant store loads. */
328
+ current;
329
+ /**
330
+ * Gets valid OAuth tokens, triggering refresh if needed.
331
+ * Coalesces concurrent requests to avoid duplicate refresh calls.
332
+ */
333
+ async get() {
334
+ if (this.inflight) {
335
+ return this.inflight;
336
+ }
337
+ this.inflight = this.loadFresh().then((tokens) => {
338
+ this.current = tokens;
339
+ this.inflight = void 0;
340
+ return tokens;
341
+ }).catch((error) => {
342
+ this.inflight = void 0;
343
+ throw error;
344
+ });
345
+ return this.inflight;
346
+ }
347
+ /**
348
+ * Loads fresh tokens, optionally refreshing if expired or near expiry.
349
+ * Derives account ID from JWT claims if not explicitly provided.
350
+ */
351
+ async loadFresh() {
352
+ let tokens = this.current ?? await this.store.load();
353
+ if (!tokens?.accessToken) {
354
+ throw new OpenAIOAuthError("auth_failed", "OpenAI OAuth access token is missing.");
355
+ }
356
+ const now = this.settings.now?.() ?? Date.now();
357
+ const refreshMarginMs = this.settings.refreshMarginMs ?? DEFAULT_REFRESH_MARGIN_MS;
358
+ if (needsRefresh(tokens, now, refreshMarginMs)) {
359
+ const refreshed = await refreshOpenAITokens({
360
+ tokens,
361
+ fetch: this.fetch,
362
+ clientId: this.settings.clientId,
363
+ issuer: this.settings.issuer,
364
+ tokenUrl: this.settings.tokenUrl,
365
+ now: this.settings.now
366
+ });
367
+ if (refreshed) {
368
+ tokens = refreshed;
369
+ await this.store.save(tokens);
370
+ await this.settings.onTokens?.(tokens);
371
+ } else if (hasExpired(tokens, now)) {
372
+ throw new OpenAIOAuthError("auth_failed", "OpenAI OAuth access token expired and refresh failed.");
373
+ }
374
+ }
375
+ const accountId = tokens.accountId ?? deriveAccountId(tokens.idToken, tokens.accessToken);
376
+ if (!accountId) {
377
+ throw new OpenAIOAuthError(
378
+ "account_id_missing",
379
+ "OpenAI OAuth account id is missing. Store `accountId` with the tokens or include an id_token with the ChatGPT account claim."
380
+ );
381
+ }
382
+ return {
383
+ ...tokens,
384
+ accountId
385
+ };
386
+ }
387
+ };
388
+ function resolveTargetUrl(input, baseURL) {
389
+ const base = new URL(baseURL);
390
+ const parsed = /^https?:\/\//.test(input) ? new URL(input) : new URL(input, "https://codex.invalid");
391
+ let pathname = parsed.pathname;
392
+ const basePath = withoutTrailingSlash(base.pathname);
393
+ if (pathname === basePath) {
394
+ pathname = "/";
395
+ } else if (basePath && pathname.startsWith(`${basePath}/`)) {
396
+ pathname = pathname.slice(basePath.length);
397
+ }
398
+ if (pathname === "/v1") {
399
+ pathname = "/";
400
+ } else if (pathname.startsWith("/v1/")) {
401
+ pathname = pathname.slice(3);
402
+ }
403
+ if (!pathname.startsWith("/")) {
404
+ pathname = `/${pathname}`;
405
+ }
406
+ return `${base.origin}${basePath}${pathname}${parsed.search}`;
407
+ }
408
+ function browserOrigin() {
409
+ const maybeWindow = globalThis.window;
410
+ return typeof maybeWindow?.location?.origin === "string" ? maybeWindow.location.origin.replace(/\/$/, "") : void 0;
411
+ }
412
+ function resolveBrowserProxyUrl(target, baseURL, settings) {
413
+ const origin = browserOrigin();
414
+ if (!origin || settings.browserProxyBaseUrl === false) {
415
+ return void 0;
416
+ }
417
+ const proxyBase = settings.browserProxyBaseUrl ?? DEFAULT_BROWSER_PROXY_BASE_URL;
418
+ const absoluteProxyBase = /^https?:\/\//.test(proxyBase) ? proxyBase.replace(/\/$/, "") : `${origin}${proxyBase.startsWith("/") ? "" : "/"}${proxyBase}`.replace(/\/$/, "");
419
+ const upstreamBasePath = withoutTrailingSlash(new URL(baseURL).pathname);
420
+ let pathname = target.pathname;
421
+ if (upstreamBasePath && pathname.startsWith(`${upstreamBasePath}/`)) {
422
+ pathname = pathname.slice(upstreamBasePath.length);
423
+ }
424
+ return `${absoluteProxyBase}${pathname}${target.search}`;
425
+ }
426
+ async function readRequestParts(input, init) {
427
+ if (input instanceof Request) {
428
+ const headers = new Headers(input.headers);
429
+ if (init?.headers) {
430
+ new Headers(init.headers).forEach((value, key) => headers.set(key, value));
431
+ }
432
+ return {
433
+ url: input.url,
434
+ method: init?.method ?? input.method,
435
+ headers,
436
+ body: init?.body ?? (input.body == null ? void 0 : await input.clone().text()),
437
+ signal: init?.signal ?? input.signal
438
+ };
439
+ }
440
+ return {
441
+ url: String(input),
442
+ method: init?.method,
443
+ headers: new Headers(init?.headers),
444
+ body: init?.body,
445
+ signal: init?.signal
446
+ };
447
+ }
448
+ async function decodeBody(body) {
449
+ if (body == null) {
450
+ return void 0;
451
+ }
452
+ if (typeof body === "string") {
453
+ return body;
454
+ }
455
+ if (body instanceof URLSearchParams || body instanceof FormData || body instanceof ReadableStream) {
456
+ return void 0;
457
+ }
458
+ if (body instanceof Blob) {
459
+ return body.text();
460
+ }
461
+ if (body instanceof ArrayBuffer) {
462
+ return new TextDecoder().decode(body);
463
+ }
464
+ if (ArrayBuffer.isView(body)) {
465
+ return new TextDecoder().decode(body);
466
+ }
467
+ return void 0;
468
+ }
469
+ function normalizeCodexResponsesBody(body, options = {}) {
470
+ const normalized = { ...body };
471
+ if (typeof normalized.instructions !== "string") {
472
+ normalized.instructions = options.instructions ?? DEFAULT_INSTRUCTIONS;
473
+ }
474
+ if (normalized.store === void 0) {
475
+ normalized.store = options.store ?? false;
476
+ }
477
+ delete normalized.max_output_tokens;
478
+ return normalized;
479
+ }
480
+ async function prepareBody(pathname, headers, body, settings) {
481
+ if (!pathname.endsWith("/responses")) {
482
+ return body;
483
+ }
484
+ const contentType = headers.get("content-type");
485
+ if (contentType && !contentType.includes("application/json")) {
486
+ return body;
487
+ }
488
+ const bodyText = await decodeBody(body);
489
+ if (typeof bodyText !== "string") {
490
+ return body;
491
+ }
492
+ try {
493
+ const parsed = JSON.parse(bodyText);
494
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
495
+ return body;
496
+ }
497
+ return JSON.stringify(normalizeCodexResponsesBody(parsed, settings));
498
+ } catch {
499
+ return body;
500
+ }
501
+ }
502
+ function createCodexOAuthFetch(settings = {}) {
503
+ const fetch = pickFetch2(settings.fetch);
504
+ const store = createStore(settings);
505
+ const manager = new TokenManager(settings, store, fetch);
506
+ const baseURL = resolveBaseURL(settings.baseURL);
507
+ return async (input, init) => {
508
+ const request = await readRequestParts(input, init);
509
+ const targetUrl = resolveTargetUrl(request.url, baseURL);
510
+ const target = new URL(targetUrl);
511
+ const tokens = await manager.get();
512
+ const headers = new Headers(settings.headers);
513
+ request.headers.forEach((value, key) => headers.set(key, value));
514
+ headers.delete("authorization");
515
+ headers.delete("chatgpt-account-id");
516
+ headers.delete("openai-beta");
517
+ headers.set("Authorization", `Bearer ${tokens.accessToken}`);
518
+ headers.set("ChatGPT-Account-Id", tokens.accountId);
519
+ headers.set("OpenAI-Beta", "responses=experimental");
520
+ if (settings.originator !== false && !headers.has("originator")) {
521
+ headers.set("originator", settings.originator ?? DEFAULT_ORIGINATOR);
522
+ }
523
+ const body = await prepareBody(target.pathname, headers, request.body, settings);
524
+ return fetch(resolveBrowserProxyUrl(target, baseURL, settings) ?? target.toString(), {
525
+ method: request.method ?? init?.method,
526
+ headers,
527
+ body,
528
+ signal: request.signal ?? void 0
529
+ });
530
+ };
531
+ }
532
+ function createCodexOAuthClient(settings = {}) {
533
+ const baseURL = resolveBaseURL(settings.baseURL);
534
+ const fetch = createCodexOAuthFetch(settings);
535
+ return {
536
+ baseURL,
537
+ fetch,
538
+ request: (path, init) => fetch(resolveTargetUrl(path, baseURL), init)
539
+ };
540
+ }
541
+
542
+ // src/proxy.ts
543
+ function pickFetch3(customFetch) {
544
+ if (typeof customFetch === "function") return customFetch;
545
+ if (typeof globalThis.fetch === "function") return globalThis.fetch.bind(globalThis);
546
+ throw new Error("A fetch implementation is required for OpenAI Codex proxy handlers.");
547
+ }
548
+ function noStoreText(text, status) {
549
+ return new Response(text, {
550
+ status,
551
+ headers: {
552
+ "Content-Type": "text/plain; charset=utf-8",
553
+ "Cache-Control": "no-store"
554
+ }
555
+ });
556
+ }
557
+ async function requestBody(request, options) {
558
+ const text = await request.text();
559
+ if (!text.trim()) return text;
560
+ try {
561
+ const parsed = JSON.parse(text);
562
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return text;
563
+ return JSON.stringify(normalizeCodexResponsesBody(parsed, options));
564
+ } catch {
565
+ return text;
566
+ }
567
+ }
568
+ function createOpenAIOAuthProxy(options = {}) {
569
+ const fetch = pickFetch3(options.fetch);
570
+ const baseURL = (options.baseURL ?? DEFAULT_CODEX_BASE_URL).replace(/\/$/, "");
571
+ return {
572
+ async responses(request) {
573
+ const authorization = request.headers.get("authorization") ?? "";
574
+ const accountId = request.headers.get("chatgpt-account-id") ?? "";
575
+ if (!authorization.trim() || !accountId.trim()) {
576
+ return noStoreText("Missing OpenAI OAuth credentials.", 401);
577
+ }
578
+ const upstream = await fetch(`${baseURL}/responses${new URL(request.url).search}`, {
579
+ method: "POST",
580
+ headers: {
581
+ "Content-Type": "application/json",
582
+ Authorization: authorization,
583
+ "ChatGPT-Account-Id": accountId,
584
+ "OpenAI-Beta": "responses=experimental",
585
+ ...options.originator === false ? {} : { originator: options.originator ?? "openai-codex-oauth" }
586
+ },
587
+ body: await requestBody(request, options)
588
+ });
589
+ return new Response(upstream.body, {
590
+ status: upstream.status,
591
+ headers: {
592
+ "Content-Type": upstream.headers.get("Content-Type") ?? "application/json",
593
+ "Cache-Control": upstream.headers.get("Cache-Control") ?? "no-store"
594
+ }
595
+ });
596
+ }
597
+ };
598
+ }
19
599
 
20
600
  // src/provider.ts
21
- import { createOpenAI } from "@ai-sdk/openai";
22
- import { NoSuchModelError } from "@ai-sdk/provider";
601
+ var import_openai = require("@ai-sdk/openai");
602
+ var import_provider = require("@ai-sdk/provider");
23
603
 
24
604
  // src/stream-to-generate.ts
25
605
  var emptyUsage = () => ({
@@ -203,7 +783,7 @@ var StreamOnlyLanguageModel = class {
203
783
  function createOpenAIOAuth(settings = {}) {
204
784
  const providerName = settings.name ?? "openai-oauth";
205
785
  const oauthFetch = createCodexOAuthFetch(settings);
206
- const openai = createOpenAI({
786
+ const openai = (0, import_openai.createOpenAI)({
207
787
  apiKey: "oauth",
208
788
  baseURL: settings.baseURL ?? DEFAULT_CODEX_BASE_URL,
209
789
  name: providerName,
@@ -215,14 +795,15 @@ function createOpenAIOAuth(settings = {}) {
215
795
  provider.languageModel = createLanguageModel;
216
796
  provider.responses = createLanguageModel;
217
797
  provider.embeddingModel = (modelId) => {
218
- throw new NoSuchModelError({ modelId, modelType: "embeddingModel" });
798
+ throw new import_provider.NoSuchModelError({ modelId, modelType: "embeddingModel" });
219
799
  };
220
800
  provider.imageModel = (modelId) => {
221
- throw new NoSuchModelError({ modelId, modelType: "imageModel" });
801
+ throw new import_provider.NoSuchModelError({ modelId, modelType: "imageModel" });
222
802
  };
223
803
  return provider;
224
804
  }
225
- export {
805
+ // Annotate the CommonJS export names for ESM import in node:
806
+ 0 && (module.exports = {
226
807
  DEFAULT_CLIENT_ID,
227
808
  DEFAULT_CODEX_BASE_URL,
228
809
  DEFAULT_ISSUER,
@@ -238,5 +819,5 @@ export {
238
819
  parseJwtClaims,
239
820
  refreshOpenAITokens,
240
821
  startOpenAIDeviceFlow
241
- };
822
+ });
242
823
  //# sourceMappingURL=index.js.map