openai-oauth 1.0.2 → 2.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,65 +1,23 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  DEFAULT_PORT,
4
- createCodexOAuthClient,
5
- resolveAuthFileCandidates,
6
4
  resolveOpenAIOAuthModels,
5
+ runOpenAIOAuthLogin,
7
6
  startOpenAIOAuthServer
8
- } from "./chunk-2AENSHRT.js";
7
+ } from "./chunk-XZLFK5NT.js";
9
8
 
10
9
  // src/cli-app.ts
11
10
  import { access } from "fs/promises";
11
+ import { createInterface } from "readline/promises";
12
+ import {
13
+ createCodexOAuthClient,
14
+ resolveAuthFileCandidates,
15
+ resolveCodexAuthFilePath
16
+ } from "@openai-oauth/core";
17
+ import { openaiCredentials } from "@openai-oauth/local";
12
18
  import yargs from "yargs";
13
19
  import { hideBin } from "yargs/helpers";
14
20
 
15
- // package.json
16
- var package_default = {
17
- name: "openai-oauth",
18
- version: "1.0.2",
19
- description: "Free OpenAI API access with your ChatGPT account.",
20
- type: "module",
21
- bin: {
22
- "openai-oauth": "./dist/cli.js"
23
- },
24
- exports: {
25
- ".": {
26
- types: "./dist/index.d.ts",
27
- default: "./dist/index.js"
28
- }
29
- },
30
- files: [
31
- "dist"
32
- ],
33
- scripts: {
34
- build: "tsup src/index.ts src/cli.ts --format esm --dts --outDir dist --clean",
35
- dev: "bun ./src/cli.ts",
36
- prepublishOnly: "bun run build",
37
- typecheck: "tsc --noEmit",
38
- test: "vitest run",
39
- "test:live": "LIVE_CODEX_E2E=1 vitest run test/live.e2e.test.ts"
40
- },
41
- dependencies: {
42
- ai: "6.0.116",
43
- yargs: "^17.7.2"
44
- },
45
- devDependencies: {
46
- "@ai-sdk/openai": "3.0.41",
47
- "@types/node": "20.17.24",
48
- "@types/yargs": "^17.0.33",
49
- "openai-oauth-core": "workspace:*",
50
- "openai-oauth-provider": "workspace:*",
51
- typescript: "latest",
52
- vitest: "latest",
53
- zod: "^3.25.76"
54
- },
55
- author: "EvanZhouDev",
56
- license: "AGPL-3.0-only",
57
- bugs: {
58
- url: "https://github.com/EvanZhouDev/openai-oauth/issues"
59
- },
60
- homepage: "https://github.com/EvanZhouDev/openai-oauth#readme"
61
- };
62
-
63
21
  // src/cli-logging.ts
64
22
  var ansi = {
65
23
  dim: "\x1B[2m",
@@ -146,13 +104,17 @@ var compareSemver = (left, right) => {
146
104
  }
147
105
  return 0;
148
106
  };
149
- var fetchLatestVersion = async (fetchImpl) => {
107
+ var fetchLatestVersion = async (fetchImpl, signal) => {
150
108
  try {
151
- const response = await fetchImpl(REGISTRY_URL, {
109
+ const requestInit = {
152
110
  headers: {
153
111
  accept: "application/json"
154
112
  }
155
- });
113
+ };
114
+ if (signal) {
115
+ requestInit.signal = signal;
116
+ }
117
+ const response = await fetchImpl(REGISTRY_URL, requestInit);
156
118
  if (!response.ok) {
157
119
  return void 0;
158
120
  }
@@ -167,9 +129,18 @@ var checkForOpenAIOAuthUpdates = async (currentVersion, dependencies = {}) => {
167
129
  if (normalizedCurrentVersion == null) {
168
130
  return;
169
131
  }
132
+ const abortController = new AbortController();
133
+ const timeout = setTimeout(() => {
134
+ abortController.abort();
135
+ }, dependencies.timeoutMs ?? 1500);
136
+ if (typeof timeout === "object" && "unref" in timeout) {
137
+ timeout.unref();
138
+ }
170
139
  const latestVersion = await fetchLatestVersion(
171
- dependencies.fetchImpl ?? globalThis.fetch
140
+ dependencies.fetchImpl ?? globalThis.fetch,
141
+ abortController.signal
172
142
  );
143
+ clearTimeout(timeout);
173
144
  if (latestVersion == null) {
174
145
  return;
175
146
  }
@@ -182,7 +153,13 @@ Run \`npx openai-oauth@latest\` to use the newest version.`
182
153
  );
183
154
  };
184
155
 
156
+ // src/version.ts
157
+ var packageVersion = "2.0.0-beta.0";
158
+
185
159
  // src/cli-app.ts
160
+ var defaultUpdateCheckWarning = (message) => {
161
+ console.error(message);
162
+ };
186
163
  var parseModels = (value) => {
187
164
  if (typeof value !== "string") {
188
165
  return void 0;
@@ -195,31 +172,34 @@ var helpLines = [
195
172
  "",
196
173
  "Usage",
197
174
  " npx openai-oauth@latest [options]",
175
+ " npx openai-oauth@latest login [options]",
198
176
  "",
199
177
  "Options",
200
- " --host <host> Host interface to bind to.",
201
- " --port <port> Port to listen on. Default: 10531",
178
+ " --host <host> Proxy host. Login callback always listens on loopback.",
179
+ " --port <port> Proxy port. Default: 10531.",
202
180
  " --models <ids> Comma-separated model ids to expose from /v1/models.",
203
181
  " --codex-version <version> Codex API version to use for model discovery.",
204
182
  " --base-url <url> Override the upstream Codex base URL.",
205
183
  " --oauth-client-id <id> Override the OAuth client id used for refresh.",
206
184
  " --oauth-token-url <url> Override the OAuth token URL used for refresh.",
207
185
  " --oauth-file <path> Path to the local auth.json file.",
186
+ " --no-open Print the login URL without opening a browser.",
187
+ " --login-timeout-ms <ms> Login timeout. Default: 300000",
208
188
  "",
209
189
  "Flags",
210
190
  " --help Show help",
211
- ` --version Show version (${package_default.version})`,
191
+ ` --version Show version (${packageVersion})`,
212
192
  "",
213
193
  "Notes",
214
- " If no auth file is found, run: npx @openai/codex login",
194
+ " If no auth file is found, run: npx openai-oauth login",
215
195
  " By default, available models are discovered from your account."
216
196
  ];
217
197
  var createCliParser = (argv) => yargs(argv).scriptName("openai-oauth").strict().help(false).version(false).option("host", {
218
198
  type: "string",
219
- describe: "Host interface to bind to."
199
+ describe: "Proxy host. Login callback always listens on loopback."
220
200
  }).option("port", {
221
201
  type: "number",
222
- describe: "Port to listen on. Default: 10531"
202
+ describe: "Proxy port. Default: 10531."
223
203
  }).option("models", {
224
204
  type: "string",
225
205
  describe: "Comma-separated model ids to expose from /v1/models.",
@@ -239,13 +219,24 @@ var createCliParser = (argv) => yargs(argv).scriptName("openai-oauth").strict().
239
219
  }).option("oauth-file", {
240
220
  type: "string",
241
221
  describe: "Path to the local auth.json file."
222
+ }).option("open", {
223
+ type: "boolean",
224
+ default: true,
225
+ describe: "Open the login URL in a browser."
226
+ }).option("login-timeout-ms", {
227
+ type: "number",
228
+ describe: "Login timeout in milliseconds. Default: 300000"
242
229
  });
243
230
  var isHelpFlag = (argv) => argv.includes("--help") || argv.includes("-h");
244
231
  var isVersionFlag = (argv) => argv.includes("--version");
245
232
  var toHelpMessage = () => helpLines.join("\n");
246
233
  var parseCliArgs = (argv) => {
247
- const parsed = createCliParser(argv).parseSync();
234
+ const command = argv[0] === "login" ? "login" : "serve";
235
+ const parsed = createCliParser(
236
+ command === "login" ? argv.slice(1) : argv
237
+ ).parseSync();
248
238
  return {
239
+ command,
249
240
  host: parsed.host,
250
241
  port: parsed.port,
251
242
  models: parsed.models,
@@ -253,7 +244,9 @@ var parseCliArgs = (argv) => {
253
244
  baseURL: parsed.baseUrl,
254
245
  clientId: parsed.oauthClientId,
255
246
  tokenUrl: parsed.oauthTokenUrl,
256
- authFilePath: parsed.oauthFile
247
+ authFilePath: parsed.oauthFile,
248
+ openBrowser: parsed.open,
249
+ loginTimeoutMs: parsed.loginTimeoutMs
257
250
  };
258
251
  };
259
252
  var toServerOptions = (args) => ({
@@ -266,6 +259,13 @@ var toServerOptions = (args) => ({
266
259
  tokenUrl: args.tokenUrl,
267
260
  authFilePath: args.authFilePath
268
261
  });
262
+ var toLoginOptions = (args) => ({
263
+ clientId: args.clientId,
264
+ tokenUrl: args.tokenUrl,
265
+ authFilePath: args.authFilePath,
266
+ openBrowser: args.openBrowser,
267
+ timeoutMs: args.loginTimeoutMs
268
+ });
269
269
  var findExistingAuthFile = async (authFilePath) => {
270
270
  for (const candidate of resolveAuthFileCandidates(authFilePath)) {
271
271
  try {
@@ -276,37 +276,166 @@ var findExistingAuthFile = async (authFilePath) => {
276
276
  }
277
277
  return void 0;
278
278
  };
279
+ var findExistingCodexAuthFile = async (authFilePath) => {
280
+ const candidate = resolveCodexAuthFilePath(authFilePath);
281
+ try {
282
+ await access(candidate);
283
+ return candidate;
284
+ } catch {
285
+ return void 0;
286
+ }
287
+ };
288
+ var canPrompt = () => Boolean(process.stdin.isTTY && process.stdout.isTTY);
289
+ var parseConfirmationAnswer = (answer, defaultValue) => {
290
+ const normalized = answer.trim().toLowerCase();
291
+ if (!normalized) {
292
+ return defaultValue;
293
+ }
294
+ return normalized === "y" || normalized === "yes";
295
+ };
296
+ var confirm = async (question, defaultValue) => {
297
+ const suffix = defaultValue ? " [Y/n] " : " [y/N] ";
298
+ const readline = createInterface({
299
+ input: process.stdin,
300
+ output: process.stdout
301
+ });
302
+ try {
303
+ const answer = await readline.question(`${question}${suffix}`);
304
+ return parseConfirmationAnswer(answer, defaultValue);
305
+ } finally {
306
+ readline.close();
307
+ }
308
+ };
309
+ var toMissingAuthFilePrompt = (authFilePath) => {
310
+ const writePath = resolveCodexAuthFilePath(authFilePath);
311
+ return [
312
+ "No OpenAI OAuth credentials were found.",
313
+ `Sign in with ChatGPT now? This will write credentials to ${writePath}.`
314
+ ].join("\n");
315
+ };
316
+ var toOverwriteAuthFilePrompt = (authFilePath) => [
317
+ `OpenAI OAuth credentials already exist at ${authFilePath}.`,
318
+ "Sign in with ChatGPT again and overwrite them?"
319
+ ].join("\n");
279
320
  var toMissingAuthFileMessage = (authFilePath) => {
280
321
  if (authFilePath) {
281
322
  return [
282
323
  `No auth file was found at ${authFilePath}.`,
283
- "Run `npx @openai/codex login` and try again."
324
+ "Run `npx openai-oauth login` and try again."
284
325
  ].join("\n");
285
326
  }
286
327
  const candidates = resolveAuthFileCandidates(void 0);
287
328
  return [
288
329
  `No auth file was found in the default search paths: ${candidates.join(", ")}.`,
289
- "Run `npx @openai/codex login` and try again."
330
+ "Run `npx openai-oauth login` and try again."
290
331
  ].join("\n");
291
332
  };
333
+ var runUpdateCheck = () => checkForOpenAIOAuthUpdates(packageVersion, {
334
+ onWarning: defaultUpdateCheckWarning
335
+ });
336
+ var createLoginCancellation = () => {
337
+ const abortController = new AbortController();
338
+ let signalName;
339
+ const abort = (receivedSignal) => {
340
+ signalName = receivedSignal;
341
+ abortController.abort();
342
+ };
343
+ const onSigint = () => abort("SIGINT");
344
+ const onSigterm = () => abort("SIGTERM");
345
+ process.once("SIGINT", onSigint);
346
+ process.once("SIGTERM", onSigterm);
347
+ return {
348
+ signal: abortController.signal,
349
+ exitCode: () => signalName === "SIGTERM" ? 143 : 130,
350
+ dispose: () => {
351
+ process.off("SIGINT", onSigint);
352
+ process.off("SIGTERM", onSigterm);
353
+ }
354
+ };
355
+ };
356
+ var isLoginCancelledError = (error) => error instanceof Error && error.message === "OpenAI OAuth login cancelled.";
357
+ var runLoginWithCancellation = async (options) => {
358
+ const cancellation = createLoginCancellation();
359
+ try {
360
+ await runOpenAIOAuthLogin({
361
+ ...options,
362
+ signal: cancellation.signal
363
+ });
364
+ return true;
365
+ } catch (error) {
366
+ if (cancellation.signal.aborted && isLoginCancelledError(error)) {
367
+ process.exitCode = cancellation.exitCode();
368
+ console.error("\nLogin cancelled.");
369
+ return false;
370
+ }
371
+ throw error;
372
+ } finally {
373
+ cancellation.dispose();
374
+ }
375
+ };
292
376
  var runCli = async (argv = hideBin(process.argv)) => {
293
377
  if (isHelpFlag(argv)) {
294
378
  console.log(toHelpMessage());
295
379
  return;
296
380
  }
297
381
  if (isVersionFlag(argv)) {
298
- console.log(package_default.version);
382
+ console.log(packageVersion);
299
383
  return;
300
384
  }
301
385
  installCliWarningLogger();
302
386
  const args = parseCliArgs(argv);
387
+ const updateCheck = runUpdateCheck();
388
+ if (args.command === "login") {
389
+ await updateCheck;
390
+ const loginOptions = toLoginOptions(args);
391
+ const existingAuthFile2 = await findExistingCodexAuthFile(
392
+ loginOptions.authFilePath
393
+ );
394
+ if (existingAuthFile2) {
395
+ if (!canPrompt()) {
396
+ throw new Error(
397
+ [
398
+ `OpenAI OAuth credentials already exist at ${existingAuthFile2}.`,
399
+ "Run `npx openai-oauth login` in an interactive terminal to confirm overwrite."
400
+ ].join("\n")
401
+ );
402
+ }
403
+ const shouldOverwrite = await confirm(
404
+ toOverwriteAuthFilePrompt(existingAuthFile2),
405
+ false
406
+ );
407
+ if (!shouldOverwrite) {
408
+ console.log("Login cancelled.");
409
+ return;
410
+ }
411
+ }
412
+ await runLoginWithCancellation(loginOptions);
413
+ return;
414
+ }
303
415
  const options = toServerOptions(args);
304
416
  const existingAuthFile = await findExistingAuthFile(options.authFilePath);
305
417
  if (!existingAuthFile) {
306
- throw new Error(toMissingAuthFileMessage(options.authFilePath));
418
+ await updateCheck;
419
+ if (!canPrompt()) {
420
+ throw new Error(toMissingAuthFileMessage(options.authFilePath));
421
+ }
422
+ const shouldLogin = await confirm(
423
+ toMissingAuthFilePrompt(options.authFilePath),
424
+ true
425
+ );
426
+ if (!shouldLogin) {
427
+ console.log("Login cancelled.");
428
+ return;
429
+ }
430
+ const didLogin = await runLoginWithCancellation(toLoginOptions(args));
431
+ if (!didLogin) {
432
+ return;
433
+ }
307
434
  }
435
+ const auth = openaiCredentials(options);
308
436
  const client = createCodexOAuthClient({
309
437
  ...options,
438
+ auth: () => auth.getSession(),
310
439
  responsesState: false
311
440
  });
312
441
  const availableModels = await resolveOpenAIOAuthModels(
@@ -320,12 +449,6 @@ var runCli = async (argv = hideBin(process.argv)) => {
320
449
  }
321
450
  );
322
451
  const server = await startOpenAIOAuthServer(options);
323
- if ((options.port ?? DEFAULT_PORT) !== server.port) {
324
- console.log(
325
- `Port ${options.port ?? DEFAULT_PORT} was unavailable. Using port ${server.port} instead.
326
- `
327
- );
328
- }
329
452
  console.log(
330
453
  toStartupMessage(
331
454
  `http://${server.host}:${server.port}/v1`,
@@ -335,11 +458,7 @@ var runCli = async (argv = hideBin(process.argv)) => {
335
458
  }
336
459
  )
337
460
  );
338
- void checkForOpenAIOAuthUpdates(package_default.version, {
339
- onWarning: (message) => {
340
- console.error(message);
341
- }
342
- });
461
+ void updateCheck;
343
462
  const shutdown = async () => {
344
463
  await server.close();
345
464
  process.exit(0);
package/dist/index.d.ts CHANGED
@@ -1,57 +1,20 @@
1
+ import { SavedAuthTokens } from '@openai-oauth/core';
1
2
  import { Server } from 'node:http';
2
- import { FetchFunction } from '@ai-sdk/provider-utils';
3
+ import { LocalOpenAIOAuthOptions } from '@openai-oauth/local';
3
4
 
4
- type AuthLoaderOptions = {
5
+ type OpenAIOAuthLoginOptions = {
6
+ host?: string;
7
+ redirectHost?: string;
5
8
  clientId?: string;
6
- issuer?: string;
7
9
  tokenUrl?: string;
8
10
  authFilePath?: string;
9
- fetch: FetchFunction;
10
- ensureFresh?: boolean;
11
- now?: () => Date;
12
- };
13
-
14
- type JsonRecord = Record<string, unknown>;
15
- type CodexResponsesStateSnapshot = {
16
- items: Array<{
17
- id: string;
18
- item: JsonRecord;
19
- }>;
20
- responses: Array<{
21
- id: string;
22
- input: unknown[];
23
- output: JsonRecord[];
24
- }>;
25
- };
26
- type CodexResponsesStateOptions = {
27
- snapshot?: CodexResponsesStateSnapshot;
28
- onChange?: (snapshot: CodexResponsesStateSnapshot) => void;
29
- };
30
- declare class CodexResponsesState {
31
- private readonly items;
32
- private readonly responses;
33
- private readonly pendingCaptures;
34
- private readonly onChange?;
35
- constructor(options?: CodexResponsesStateOptions);
36
- waitForPendingCaptures(): Promise<void>;
37
- trackPendingCapture(promise: Promise<void>): void;
38
- requiresCachedState(body: JsonRecord): boolean;
39
- expandRequestBody(body: JsonRecord): JsonRecord;
40
- rememberResponse(response: unknown, requestBody?: JsonRecord): void;
41
- snapshot(): CodexResponsesStateSnapshot;
42
- private expandInput;
43
- private emitChange;
44
- }
45
-
46
- type CodexOAuthSettings = Omit<AuthLoaderOptions, "fetch"> & {
47
- baseURL?: string;
48
- codexVersion?: string;
49
- fetch?: FetchFunction;
50
- headers?: Record<string, string>;
51
- instructions?: string;
52
- store?: boolean;
53
- responsesState?: CodexResponsesState | false;
11
+ openBrowser?: boolean;
12
+ timeoutMs?: number;
13
+ fetch?: typeof fetch;
14
+ onMessage?: (message: string) => void;
15
+ signal?: AbortSignal;
54
16
  };
17
+ declare const runOpenAIOAuthLogin: (options?: OpenAIOAuthLoginOptions) => Promise<SavedAuthTokens>;
55
18
 
56
19
  type JsonValue = null | boolean | number | string | JsonValue[] | JsonObject;
57
20
  type JsonObject = {
@@ -134,7 +97,7 @@ type OpenAIOAuthServerLogEvent = ({
134
97
  requestId: string;
135
98
  };
136
99
  declare const defaultOpenAIOAuthModels: readonly string[];
137
- type OpenAIOAuthServerOptions = Omit<CodexOAuthSettings, "responsesState"> & {
100
+ type OpenAIOAuthServerOptions = LocalOpenAIOAuthOptions & {
138
101
  host?: string;
139
102
  port?: number;
140
103
  models?: string[];
@@ -152,4 +115,4 @@ type RunningOpenAIOAuthServer = {
152
115
  declare const createOpenAIOAuthFetchHandler: (settings?: OpenAIOAuthServerOptions) => ((request: Request) => Promise<Response>);
153
116
  declare const startOpenAIOAuthServer: (settings?: OpenAIOAuthServerOptions) => Promise<RunningOpenAIOAuthServer>;
154
117
 
155
- export { type OpenAIOAuthServerLogEvent, type OpenAIOAuthServerOptions, type RunningOpenAIOAuthServer, createOpenAIOAuthFetchHandler, defaultOpenAIOAuthModels, startOpenAIOAuthServer };
118
+ export { type OpenAIOAuthLoginOptions, type OpenAIOAuthServerLogEvent, type OpenAIOAuthServerOptions, type RunningOpenAIOAuthServer, createOpenAIOAuthFetchHandler, defaultOpenAIOAuthModels, runOpenAIOAuthLogin, startOpenAIOAuthServer };
package/dist/index.js CHANGED
@@ -1,10 +1,12 @@
1
1
  import {
2
2
  createOpenAIOAuthFetchHandler,
3
3
  defaultOpenAIOAuthModels,
4
+ runOpenAIOAuthLogin,
4
5
  startOpenAIOAuthServer
5
- } from "./chunk-2AENSHRT.js";
6
+ } from "./chunk-XZLFK5NT.js";
6
7
  export {
7
8
  createOpenAIOAuthFetchHandler,
8
9
  defaultOpenAIOAuthModels,
10
+ runOpenAIOAuthLogin,
9
11
  startOpenAIOAuthServer
10
12
  };
package/package.json CHANGED
@@ -1,22 +1,36 @@
1
1
  {
2
2
  "name": "openai-oauth",
3
- "version": "1.0.2",
3
+ "version": "2.0.0-beta.0",
4
4
  "description": "Free OpenAI API access with your ChatGPT account.",
5
+ "keywords": [
6
+ "openai",
7
+ "oauth",
8
+ "chatgpt",
9
+ "codex",
10
+ "cli",
11
+ "openai-compatible"
12
+ ],
5
13
  "type": "module",
14
+ "sideEffects": false,
15
+ "main": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
6
17
  "bin": {
7
- "openai-oauth": "./dist/cli.js"
18
+ "openai-oauth": "dist/cli.js"
8
19
  },
9
20
  "exports": {
10
21
  ".": {
11
22
  "types": "./dist/index.d.ts",
23
+ "import": "./dist/index.js",
12
24
  "default": "./dist/index.js"
13
25
  }
14
26
  },
15
27
  "files": [
16
- "dist"
28
+ "dist",
29
+ "README.md",
30
+ "LICENSE"
17
31
  ],
18
32
  "scripts": {
19
- "build": "tsup src/index.ts src/cli.ts --format esm --dts --outDir dist --clean",
33
+ "build": "tsup src/index.ts src/cli.ts --format esm --dts --outDir dist --clean --loader .html=text",
20
34
  "dev": "bun ./src/cli.ts",
21
35
  "prepublishOnly": "bun run build",
22
36
  "typecheck": "tsc --noEmit",
@@ -24,6 +38,9 @@
24
38
  "test:live": "LIVE_CODEX_E2E=1 vitest run test/live.e2e.test.ts"
25
39
  },
26
40
  "dependencies": {
41
+ "@openai-oauth/ai-sdk": "2.0.0-beta.0",
42
+ "@openai-oauth/core": "2.0.0-beta.0",
43
+ "@openai-oauth/local": "2.0.0-beta.0",
27
44
  "ai": "6.0.116",
28
45
  "yargs": "^17.7.2"
29
46
  },
@@ -31,14 +48,17 @@
31
48
  "@ai-sdk/openai": "3.0.41",
32
49
  "@types/node": "20.17.24",
33
50
  "@types/yargs": "^17.0.33",
34
- "openai-oauth-core": "workspace:*",
35
- "openai-oauth-provider": "workspace:*",
36
51
  "typescript": "latest",
37
52
  "vitest": "latest",
38
53
  "zod": "^3.25.76"
39
54
  },
40
55
  "author": "EvanZhouDev",
41
56
  "license": "AGPL-3.0-only",
57
+ "repository": {
58
+ "type": "git",
59
+ "url": "git+https://github.com/EvanZhouDev/openai-oauth.git",
60
+ "directory": "packages/openai-oauth"
61
+ },
42
62
  "bugs": {
43
63
  "url": "https://github.com/EvanZhouDev/openai-oauth/issues"
44
64
  },