@boxiaolanya2008/pi-ai 0.60.4
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/README.md +1198 -0
- package/bedrock-provider.d.ts +1 -0
- package/bedrock-provider.js +1 -0
- package/dist/api-registry.d.ts +20 -0
- package/dist/api-registry.d.ts.map +1 -0
- package/dist/api-registry.js +44 -0
- package/dist/api-registry.js.map +1 -0
- package/dist/bedrock-provider.d.ts +5 -0
- package/dist/bedrock-provider.d.ts.map +1 -0
- package/dist/bedrock-provider.js +6 -0
- package/dist/bedrock-provider.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +113 -0
- package/dist/cli.js.map +1 -0
- package/dist/env-api-keys.d.ts +4 -0
- package/dist/env-api-keys.d.ts.map +1 -0
- package/dist/env-api-keys.js +85 -0
- package/dist/env-api-keys.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/models.d.ts +22 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.generated.d.ts +4 -0
- package/dist/models.generated.d.ts.map +1 -0
- package/dist/models.generated.js +11 -0
- package/dist/models.generated.js.map +1 -0
- package/dist/models.js +50 -0
- package/dist/models.js.map +1 -0
- package/dist/oauth.d.ts +2 -0
- package/dist/oauth.d.ts.map +1 -0
- package/dist/oauth.js +2 -0
- package/dist/oauth.js.map +1 -0
- package/dist/providers/amazon-bedrock.d.ts +15 -0
- package/dist/providers/amazon-bedrock.d.ts.map +1 -0
- package/dist/providers/amazon-bedrock.js +552 -0
- package/dist/providers/amazon-bedrock.js.map +1 -0
- package/dist/providers/anthropic.d.ts +15 -0
- package/dist/providers/anthropic.d.ts.map +1 -0
- package/dist/providers/anthropic.js +677 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/azure-openai-responses.d.ts +12 -0
- package/dist/providers/azure-openai-responses.d.ts.map +1 -0
- package/dist/providers/azure-openai-responses.js +181 -0
- package/dist/providers/azure-openai-responses.js.map +1 -0
- package/dist/providers/github-copilot-headers.d.ts +8 -0
- package/dist/providers/github-copilot-headers.d.ts.map +1 -0
- package/dist/providers/github-copilot-headers.js +26 -0
- package/dist/providers/github-copilot-headers.js.map +1 -0
- package/dist/providers/google-gemini-cli.d.ts +15 -0
- package/dist/providers/google-gemini-cli.d.ts.map +1 -0
- package/dist/providers/google-gemini-cli.js +43 -0
- package/dist/providers/google-gemini-cli.js.map +1 -0
- package/dist/providers/google-shared.d.ts +15 -0
- package/dist/providers/google-shared.d.ts.map +1 -0
- package/dist/providers/google-shared.js +226 -0
- package/dist/providers/google-shared.js.map +1 -0
- package/dist/providers/google-vertex.d.ts +15 -0
- package/dist/providers/google-vertex.d.ts.map +1 -0
- package/dist/providers/google-vertex.js +372 -0
- package/dist/providers/google-vertex.js.map +1 -0
- package/dist/providers/google.d.ts +13 -0
- package/dist/providers/google.d.ts.map +1 -0
- package/dist/providers/google.js +351 -0
- package/dist/providers/google.js.map +1 -0
- package/dist/providers/mistral.d.ts +13 -0
- package/dist/providers/mistral.d.ts.map +1 -0
- package/dist/providers/mistral.js +489 -0
- package/dist/providers/mistral.js.map +1 -0
- package/dist/providers/openai-codex-responses.d.ts +9 -0
- package/dist/providers/openai-codex-responses.d.ts.map +1 -0
- package/dist/providers/openai-codex-responses.js +672 -0
- package/dist/providers/openai-codex-responses.js.map +1 -0
- package/dist/providers/openai-completions.d.ts +15 -0
- package/dist/providers/openai-completions.d.ts.map +1 -0
- package/dist/providers/openai-completions.js +651 -0
- package/dist/providers/openai-completions.js.map +1 -0
- package/dist/providers/openai-responses-shared.d.ts +17 -0
- package/dist/providers/openai-responses-shared.d.ts.map +1 -0
- package/dist/providers/openai-responses-shared.js +420 -0
- package/dist/providers/openai-responses-shared.js.map +1 -0
- package/dist/providers/openai-responses.d.ts +10 -0
- package/dist/providers/openai-responses.d.ts.map +1 -0
- package/dist/providers/openai-responses.js +186 -0
- package/dist/providers/openai-responses.js.map +1 -0
- package/dist/providers/register-builtins.d.ts +11 -0
- package/dist/providers/register-builtins.d.ts.map +1 -0
- package/dist/providers/register-builtins.js +138 -0
- package/dist/providers/register-builtins.js.map +1 -0
- package/dist/providers/simple-options.d.ts +8 -0
- package/dist/providers/simple-options.d.ts.map +1 -0
- package/dist/providers/simple-options.js +35 -0
- package/dist/providers/simple-options.js.map +1 -0
- package/dist/providers/transform-messages.d.ts +3 -0
- package/dist/providers/transform-messages.d.ts.map +1 -0
- package/dist/providers/transform-messages.js +130 -0
- package/dist/providers/transform-messages.js.map +1 -0
- package/dist/stream.d.ts +8 -0
- package/dist/stream.d.ts.map +1 -0
- package/dist/stream.js +27 -0
- package/dist/stream.js.map +1 -0
- package/dist/types.d.ts +213 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/event-stream.d.ts +20 -0
- package/dist/utils/event-stream.d.ts.map +1 -0
- package/dist/utils/event-stream.js +77 -0
- package/dist/utils/event-stream.js.map +1 -0
- package/dist/utils/hash.d.ts +2 -0
- package/dist/utils/hash.d.ts.map +1 -0
- package/dist/utils/hash.js +13 -0
- package/dist/utils/hash.js.map +1 -0
- package/dist/utils/json-parse.d.ts +2 -0
- package/dist/utils/json-parse.d.ts.map +1 -0
- package/dist/utils/json-parse.js +19 -0
- package/dist/utils/json-parse.js.map +1 -0
- package/dist/utils/oauth/anthropic.d.ts +4 -0
- package/dist/utils/oauth/anthropic.d.ts.map +1 -0
- package/dist/utils/oauth/anthropic.js +61 -0
- package/dist/utils/oauth/anthropic.js.map +1 -0
- package/dist/utils/oauth/github-copilot.d.ts +16 -0
- package/dist/utils/oauth/github-copilot.d.ts.map +1 -0
- package/dist/utils/oauth/github-copilot.js +247 -0
- package/dist/utils/oauth/github-copilot.js.map +1 -0
- package/dist/utils/oauth/google-antigravity.d.ts +7 -0
- package/dist/utils/oauth/google-antigravity.d.ts.map +1 -0
- package/dist/utils/oauth/google-antigravity.js +55 -0
- package/dist/utils/oauth/google-antigravity.js.map +1 -0
- package/dist/utils/oauth/index.d.ts +18 -0
- package/dist/utils/oauth/index.d.ts.map +1 -0
- package/dist/utils/oauth/index.js +72 -0
- package/dist/utils/oauth/index.js.map +1 -0
- package/dist/utils/oauth/openai-codex.d.ts +14 -0
- package/dist/utils/oauth/openai-codex.d.ts.map +1 -0
- package/dist/utils/oauth/openai-codex.js +348 -0
- package/dist/utils/oauth/openai-codex.js.map +1 -0
- package/dist/utils/oauth/pkce.d.ts +5 -0
- package/dist/utils/oauth/pkce.d.ts.map +1 -0
- package/dist/utils/oauth/pkce.js +18 -0
- package/dist/utils/oauth/pkce.js.map +1 -0
- package/dist/utils/oauth/types.d.ts +40 -0
- package/dist/utils/oauth/types.d.ts.map +1 -0
- package/dist/utils/oauth/types.js +2 -0
- package/dist/utils/oauth/types.js.map +1 -0
- package/dist/utils/overflow.d.ts +4 -0
- package/dist/utils/overflow.d.ts.map +1 -0
- package/dist/utils/overflow.js +40 -0
- package/dist/utils/overflow.js.map +1 -0
- package/dist/utils/sanitize-unicode.d.ts +2 -0
- package/dist/utils/sanitize-unicode.d.ts.map +1 -0
- package/dist/utils/sanitize-unicode.js +4 -0
- package/dist/utils/sanitize-unicode.js.map +1 -0
- package/dist/utils/typebox-helpers.d.ts +6 -0
- package/dist/utils/typebox-helpers.d.ts.map +1 -0
- package/dist/utils/typebox-helpers.js +10 -0
- package/dist/utils/typebox-helpers.js.map +1 -0
- package/dist/utils/validation.d.ts +4 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +45 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +80 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export { AnthropicOAuthProvider, loginAnthropic } from "./anthropic.js";
|
|
2
|
+
export { getGitHubCopilotBaseUrl, githubCopilotOAuthProvider, loginGitHubCopilot, normalizeDomain, refreshGitHubCopilotToken, } from "./github-copilot.js";
|
|
3
|
+
export { createGoogleAntigravityProvider } from "./google-antigravity.js";
|
|
4
|
+
export { loginOpenAICodex, openaiCodexOAuthProvider, refreshOpenAICodexToken } from "./openai-codex.js";
|
|
5
|
+
export * from "./types.js";
|
|
6
|
+
import { AnthropicOAuthProvider } from "./anthropic.js";
|
|
7
|
+
import { githubCopilotOAuthProvider } from "./github-copilot.js";
|
|
8
|
+
import { openaiCodexOAuthProvider } from "./openai-codex.js";
|
|
9
|
+
const BUILT_IN_OAUTH_PROVIDERS = [
|
|
10
|
+
AnthropicOAuthProvider,
|
|
11
|
+
githubCopilotOAuthProvider,
|
|
12
|
+
openaiCodexOAuthProvider,
|
|
13
|
+
];
|
|
14
|
+
const oauthProviderRegistry = new Map(BUILT_IN_OAUTH_PROVIDERS.map((provider) => [provider.id, provider]));
|
|
15
|
+
export function getOAuthProvider(id) {
|
|
16
|
+
return oauthProviderRegistry.get(id);
|
|
17
|
+
}
|
|
18
|
+
export function registerOAuthProvider(provider) {
|
|
19
|
+
oauthProviderRegistry.set(provider.id, provider);
|
|
20
|
+
}
|
|
21
|
+
export function unregisterOAuthProvider(id) {
|
|
22
|
+
const builtInProvider = BUILT_IN_OAUTH_PROVIDERS.find((provider) => provider.id === id);
|
|
23
|
+
if (builtInProvider) {
|
|
24
|
+
oauthProviderRegistry.set(id, builtInProvider);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
oauthProviderRegistry.delete(id);
|
|
28
|
+
}
|
|
29
|
+
export function resetOAuthProviders() {
|
|
30
|
+
oauthProviderRegistry.clear();
|
|
31
|
+
for (const provider of BUILT_IN_OAUTH_PROVIDERS) {
|
|
32
|
+
oauthProviderRegistry.set(provider.id, provider);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export function getOAuthProviders() {
|
|
36
|
+
return Array.from(oauthProviderRegistry.values());
|
|
37
|
+
}
|
|
38
|
+
export function getOAuthProviderInfoList() {
|
|
39
|
+
return getOAuthProviders().map((p) => ({
|
|
40
|
+
id: p.id,
|
|
41
|
+
name: p.name,
|
|
42
|
+
available: true,
|
|
43
|
+
}));
|
|
44
|
+
}
|
|
45
|
+
export async function refreshOAuthToken(providerId, credentials) {
|
|
46
|
+
const provider = getOAuthProvider(providerId);
|
|
47
|
+
if (!provider) {
|
|
48
|
+
throw new Error(`Unknown OAuth provider: ${providerId}`);
|
|
49
|
+
}
|
|
50
|
+
return provider.refreshToken(credentials);
|
|
51
|
+
}
|
|
52
|
+
export async function getOAuthApiKey(providerId, credentials) {
|
|
53
|
+
const provider = getOAuthProvider(providerId);
|
|
54
|
+
if (!provider) {
|
|
55
|
+
throw new Error(`Unknown OAuth provider: ${providerId}`);
|
|
56
|
+
}
|
|
57
|
+
let creds = credentials[providerId];
|
|
58
|
+
if (!creds) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
if (Date.now() >= creds.expires) {
|
|
62
|
+
try {
|
|
63
|
+
creds = await provider.refreshToken(creds);
|
|
64
|
+
}
|
|
65
|
+
catch (_error) {
|
|
66
|
+
throw new Error(`Failed to refresh OAuth token for ${providerId}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const apiKey = provider.getApiKey(creds);
|
|
70
|
+
return { newCredentials: creds, apiKey };
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/oauth/index.ts"],"names":[],"mappings":"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","sourcesContent":["export { AnthropicOAuthProvider, loginAnthropic } from \"./anthropic.js\";\nexport {\n\tgetGitHubCopilotBaseUrl,\n\tgithubCopilotOAuthProvider,\n\tloginGitHubCopilot,\n\tnormalizeDomain,\n\trefreshGitHubCopilotToken,\n} from \"./github-copilot.js\";\nexport { createGoogleAntigravityProvider } from \"./google-antigravity.js\";\nexport { loginOpenAICodex, openaiCodexOAuthProvider, refreshOpenAICodexToken } from \"./openai-codex.js\";\nexport * from \"./types.js\";\n\nimport { AnthropicOAuthProvider } from \"./anthropic.js\";\nimport { githubCopilotOAuthProvider } from \"./github-copilot.js\";\nimport { openaiCodexOAuthProvider } from \"./openai-codex.js\";\nimport type { OAuthCredentials, OAuthProviderId, OAuthProviderInfo, OAuthProviderInterface } from \"./types.js\";\n\nconst BUILT_IN_OAUTH_PROVIDERS: OAuthProviderInterface[] = [\n\tAnthropicOAuthProvider,\n\tgithubCopilotOAuthProvider,\n\topenaiCodexOAuthProvider,\n];\n\nconst oauthProviderRegistry = new Map<string, OAuthProviderInterface>(\n\tBUILT_IN_OAUTH_PROVIDERS.map((provider) => [provider.id, provider]),\n);\n\nexport function getOAuthProvider(id: OAuthProviderId): OAuthProviderInterface | undefined {\n\treturn oauthProviderRegistry.get(id);\n}\n\nexport function registerOAuthProvider(provider: OAuthProviderInterface): void {\n\toauthProviderRegistry.set(provider.id, provider);\n}\n\nexport function unregisterOAuthProvider(id: string): void {\n\tconst builtInProvider = BUILT_IN_OAUTH_PROVIDERS.find((provider) => provider.id === id);\n\tif (builtInProvider) {\n\t\toauthProviderRegistry.set(id, builtInProvider);\n\t\treturn;\n\t}\n\toauthProviderRegistry.delete(id);\n}\n\nexport function resetOAuthProviders(): void {\n\toauthProviderRegistry.clear();\n\tfor (const provider of BUILT_IN_OAUTH_PROVIDERS) {\n\t\toauthProviderRegistry.set(provider.id, provider);\n\t}\n}\n\nexport function getOAuthProviders(): OAuthProviderInterface[] {\n\treturn Array.from(oauthProviderRegistry.values());\n}\n\nexport function getOAuthProviderInfoList(): OAuthProviderInfo[] {\n\treturn getOAuthProviders().map((p) => ({\n\t\tid: p.id,\n\t\tname: p.name,\n\t\tavailable: true,\n\t}));\n}\n\nexport async function refreshOAuthToken(\n\tproviderId: OAuthProviderId,\n\tcredentials: OAuthCredentials,\n): Promise<OAuthCredentials> {\n\tconst provider = getOAuthProvider(providerId);\n\tif (!provider) {\n\t\tthrow new Error(`Unknown OAuth provider: ${providerId}`);\n\t}\n\treturn provider.refreshToken(credentials);\n}\n\nexport async function getOAuthApiKey(\n\tproviderId: OAuthProviderId,\n\tcredentials: Record<string, OAuthCredentials>,\n): Promise<{ newCredentials: OAuthCredentials; apiKey: string } | null> {\n\tconst provider = getOAuthProvider(providerId);\n\tif (!provider) {\n\t\tthrow new Error(`Unknown OAuth provider: ${providerId}`);\n\t}\n\tlet creds = credentials[providerId];\n\tif (!creds) {\n\t\treturn null;\n\t}\n\tif (Date.now() >= creds.expires) {\n\t\ttry {\n\t\t\tcreds = await provider.refreshToken(creds);\n\t\t} catch (_error) {\n\t\t\tthrow new Error(`Failed to refresh OAuth token for ${providerId}`);\n\t\t}\n\t}\n\tconst apiKey = provider.getApiKey(creds);\n\treturn { newCredentials: creds, apiKey };\n}\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { OAuthCredentials, OAuthPrompt, OAuthProviderInterface } from "./types.js";
|
|
2
|
+
export declare function loginOpenAICodex(options: {
|
|
3
|
+
onAuth: (info: {
|
|
4
|
+
url: string;
|
|
5
|
+
instructions?: string;
|
|
6
|
+
}) => void;
|
|
7
|
+
onPrompt: (prompt: OAuthPrompt) => Promise<string>;
|
|
8
|
+
onProgress?: (message: string) => void;
|
|
9
|
+
onManualCodeInput?: () => Promise<string>;
|
|
10
|
+
originator?: string;
|
|
11
|
+
}): Promise<OAuthCredentials>;
|
|
12
|
+
export declare function refreshOpenAICodexToken(refreshToken: string): Promise<OAuthCredentials>;
|
|
13
|
+
export declare const openaiCodexOAuthProvider: OAuthProviderInterface;
|
|
14
|
+
//# sourceMappingURL=openai-codex.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-codex.d.ts","sourceRoot":"","sources":["../../../src/utils/oauth/openai-codex.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,gBAAgB,EAAuB,WAAW,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAiP7G,wBAAsB,gBAAgB,CAAC,OAAO,EAAE;IAC/C,MAAM,EAAE,CAAC,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC/D,QAAQ,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACnD,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1C,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAiF5B;AACD,wBAAsB,uBAAuB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAe7F;AACD,eAAO,MAAM,wBAAwB,EAAE,sBAkBtC,CAAC","sourcesContent":["let _randomBytes: typeof import(\"node:crypto\").randomBytes | null = null;\nlet _http: typeof import(\"node:http\") | null = null;\nif (typeof process !== \"undefined\" && (process.versions?.node || process.versions?.bun)) {\n\timport(\"node:crypto\").then((m) => {\n\t\t_randomBytes = m.randomBytes;\n\t});\n\timport(\"node:http\").then((m) => {\n\t\t_http = m;\n\t});\n}\n\nimport { generatePKCE } from \"./pkce.js\";\nimport type { OAuthCredentials, OAuthLoginCallbacks, OAuthPrompt, OAuthProviderInterface } from \"./types.js\";\n\nconst CLIENT_ID = \"app_EMoamEEZ73f0CkXaXp7hrann\";\nconst AUTHORIZE_URL = \"https://auth.openai.com/authorize\";\nconst TOKEN_URL = \"https://auth.openai.com/token\";\nconst REDIRECT_URI = \"http://localhost:8080/oauth/callback\";\nconst SCOPE = \"openid profile email offline_access\";\nconst JWT_CLAIM_PATH = \"https://api.openai.com/v1/jwt-claim\";\nconst SUCCESS_HTML = `<!doctype html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <title>Authentication successful</title>\n</head>\n<body>\n <p>Authentication successful. Return to your terminal to continue.</p>\n</body>\n</html>`;\ntype TokenSuccess = { type: \"success\"; access: string; refresh: string; expires: number };\ntype TokenFailure = { type: \"failed\" };\ntype TokenResult = TokenSuccess | TokenFailure;\ntype JwtPayload = {\n\t[JWT_CLAIM_PATH]?: {\n\t\tchatgpt_account_id?: string;\n\t};\n\t[key: string]: unknown;\n};\nfunction createState(): string {\n\tif (!_randomBytes) {\n\t\tthrow new Error(\"OpenAI Codex OAuth is only available in Node.js environments\");\n\t}\n\treturn _randomBytes(16).toString(\"hex\");\n}\nfunction parseAuthorizationInput(input: string): { code?: string; state?: string } {\n\tconst value = input.trim();\n\tif (!value) return {};\n\ttry {\n\t\tconst url = new URL(value);\n\t\treturn {\n\t\t\tcode: url.searchParams.get(\"code\") ?? undefined,\n\t\t\tstate: url.searchParams.get(\"state\") ?? undefined,\n\t\t};\n\t} catch {}\n\tif (value.includes(\"#\")) {\n\t\tconst [code, state] = value.split(\"#\", 2);\n\t\treturn { code, state };\n\t}\n\tif (value.includes(\"code=\")) {\n\t\tconst params = new URLSearchParams(value);\n\t\treturn {\n\t\t\tcode: params.get(\"code\") ?? undefined,\n\t\t\tstate: params.get(\"state\") ?? undefined,\n\t\t};\n\t}\n\treturn { code: value };\n}\nfunction decodeJwt(token: string): JwtPayload | null {\n\ttry {\n\t\tconst parts = token.split(\".\");\n\t\tif (parts.length !== 3) return null;\n\t\tconst payload = parts[1] ?? \"\";\n\t\tconst decoded = atob(payload);\n\t\treturn JSON.parse(decoded) as JwtPayload;\n\t} catch {\n\t\treturn null;\n\t}\n}\nasync function exchangeAuthorizationCode(\n\tcode: string,\n\tverifier: string,\n\tredirectUri: string = REDIRECT_URI,\n): Promise<TokenResult> {\n\tconst response = await fetch(TOKEN_URL, {\n\t\tmethod: \"POST\",\n\t\theaders: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n\t\tbody: new URLSearchParams({\n\t\t\tgrant_type: \"authorization_code\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\tcode,\n\t\t\tcode_verifier: verifier,\n\t\t\tredirect_uri: redirectUri,\n\t\t}),\n\t});\n\tif (!response.ok) {\n\t\tconst text = await response.text().catch(() => \"\");\n\t\tconsole.error(\"[openai-codex] code->token failed:\", response.status, text);\n\t\treturn { type: \"failed\" };\n\t}\n\tconst json = (await response.json()) as {\n\t\taccess_token?: string;\n\t\trefresh_token?: string;\n\t\texpires_in?: number;\n\t};\n\tif (!json.access_token || !json.refresh_token || typeof json.expires_in !== \"number\") {\n\t\tconsole.error(\"[openai-codex] token response missing fields:\", json);\n\t\treturn { type: \"failed\" };\n\t}\n\treturn {\n\t\ttype: \"success\",\n\t\taccess: json.access_token,\n\t\trefresh: json.refresh_token,\n\t\texpires: Date.now() + json.expires_in * 1000,\n\t};\n}\nasync function refreshAccessToken(refreshToken: string): Promise<TokenResult> {\n\ttry {\n\t\tconst response = await fetch(TOKEN_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tgrant_type: \"refresh_token\",\n\t\t\t\trefresh_token: refreshToken,\n\t\t\t\tclient_id: CLIENT_ID,\n\t\t\t}),\n\t\t});\n\t\tif (!response.ok) {\n\t\t\tconst text = await response.text().catch(() => \"\");\n\t\t\tconsole.error(\"[openai-codex] Token refresh failed:\", response.status, text);\n\t\t\treturn { type: \"failed\" };\n\t\t}\n\t\tconst json = (await response.json()) as {\n\t\t\taccess_token?: string;\n\t\t\trefresh_token?: string;\n\t\t\texpires_in?: number;\n\t\t};\n\t\tif (!json.access_token || !json.refresh_token || typeof json.expires_in !== \"number\") {\n\t\t\tconsole.error(\"[openai-codex] Token refresh response missing fields:\", json);\n\t\t\treturn { type: \"failed\" };\n\t\t}\n\t\treturn {\n\t\t\ttype: \"success\",\n\t\t\taccess: json.access_token,\n\t\t\trefresh: json.refresh_token,\n\t\t\texpires: Date.now() + json.expires_in * 1000,\n\t\t};\n\t} catch (error) {\n\t\tconsole.error(\"[openai-codex] Token refresh error:\", error);\n\t\treturn { type: \"failed\" };\n\t}\n}\nasync function createAuthorizationFlow(\n\toriginator: string = \"pi\",\n): Promise<{ verifier: string; state: string; url: string }> {\n\tconst { verifier, challenge } = await generatePKCE();\n\tconst state = createState();\n\tconst url = new URL(AUTHORIZE_URL);\n\turl.searchParams.set(\"response_type\", \"code\");\n\turl.searchParams.set(\"client_id\", CLIENT_ID);\n\turl.searchParams.set(\"redirect_uri\", REDIRECT_URI);\n\turl.searchParams.set(\"scope\", SCOPE);\n\turl.searchParams.set(\"code_challenge\", challenge);\n\turl.searchParams.set(\"code_challenge_method\", \"S256\");\n\turl.searchParams.set(\"state\", state);\n\turl.searchParams.set(\"id_token_add_organizations\", \"true\");\n\turl.searchParams.set(\"codex_cli_simplified_flow\", \"true\");\n\turl.searchParams.set(\"originator\", originator);\n\treturn { verifier, state, url: url.toString() };\n}\ntype OAuthServerInfo = {\n\tclose: () => void;\n\tcancelWait: () => void;\n\twaitForCode: () => Promise<{ code: string } | null>;\n};\nfunction startLocalOAuthServer(state: string): Promise<OAuthServerInfo> {\n\tif (!_http) {\n\t\tthrow new Error(\"OpenAI Codex OAuth is only available in Node.js environments\");\n\t}\n\tlet lastCode: string | null = null;\n\tlet cancelled = false;\n\tconst server = _http.createServer((req, res) => {\n\t\ttry {\n\t\t\tconst url = new URL(req.url || \"\", \"http://localhost:1455\");\n\t\t\tif (url.pathname !== \"/auth/callback\") {\n\t\t\t\tres.statusCode = 404;\n\t\t\t\tres.end(\"Not found\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (url.searchParams.get(\"state\") !== state) {\n\t\t\t\tres.statusCode = 400;\n\t\t\t\tres.end(\"State mismatch\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst code = url.searchParams.get(\"code\");\n\t\t\tif (!code) {\n\t\t\t\tres.statusCode = 400;\n\t\t\t\tres.end(\"Missing authorization code\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tres.statusCode = 200;\n\t\t\tres.setHeader(\"Content-Type\", \"text/html; charset=utf-8\");\n\t\t\tres.end(SUCCESS_HTML);\n\t\t\tlastCode = code;\n\t\t} catch {\n\t\t\tres.statusCode = 500;\n\t\t\tres.end(\"Internal error\");\n\t\t}\n\t});\n\treturn new Promise((resolve) => {\n\t\tserver\n\t\t\t.listen(1455, \"127.0.0.1\", () => {\n\t\t\t\tresolve({\n\t\t\t\t\tclose: () => server.close(),\n\t\t\t\t\tcancelWait: () => {\n\t\t\t\t\t\tcancelled = true;\n\t\t\t\t\t},\n\t\t\t\t\twaitForCode: async () => {\n\t\t\t\t\t\tconst sleep = () => new Promise((r) => setTimeout(r, 100));\n\t\t\t\t\t\tfor (let i = 0; i < 600; i += 1) {\n\t\t\t\t\t\t\tif (lastCode) return { code: lastCode };\n\t\t\t\t\t\t\tif (cancelled) return null;\n\t\t\t\t\t\t\tawait sleep();\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t})\n\t\t\t.on(\"error\", (err: NodeJS.ErrnoException) => {\n\t\t\t\tconsole.error(\n\t\t\t\t\t\"[openai-codex] Failed to bind http://localhost:1455 (\",\n\t\t\t\t\terr.code,\n\t\t\t\t\t\") Falling back to manual paste.\",\n\t\t\t\t);\n\t\t\t\tresolve({\n\t\t\t\t\tclose: () => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tserver.close();\n\t\t\t\t\t\t} catch {}\n\t\t\t\t\t},\n\t\t\t\t\tcancelWait: () => {},\n\t\t\t\t\twaitForCode: async () => null,\n\t\t\t\t});\n\t\t\t});\n\t});\n}\nfunction getAccountId(accessToken: string): string | null {\n\tconst payload = decodeJwt(accessToken);\n\tconst auth = payload?.[JWT_CLAIM_PATH];\n\tconst accountId = auth?.chatgpt_account_id;\n\treturn typeof accountId === \"string\" && accountId.length > 0 ? accountId : null;\n}\nexport async function loginOpenAICodex(options: {\n\tonAuth: (info: { url: string; instructions?: string }) => void;\n\tonPrompt: (prompt: OAuthPrompt) => Promise<string>;\n\tonProgress?: (message: string) => void;\n\tonManualCodeInput?: () => Promise<string>;\n\toriginator?: string;\n}): Promise<OAuthCredentials> {\n\tconst { verifier, state, url } = await createAuthorizationFlow(options.originator);\n\tconst server = await startLocalOAuthServer(state);\n\toptions.onAuth({ url, instructions: \"A browser window should open. Complete login to finish.\" });\n\tlet code: string | undefined;\n\ttry {\n\t\tif (options.onManualCodeInput) {\n\t\t\tlet manualCode: string | undefined;\n\t\t\tlet manualError: Error | undefined;\n\t\t\tconst manualPromise = options\n\t\t\t\t.onManualCodeInput()\n\t\t\t\t.then((input) => {\n\t\t\t\t\tmanualCode = input;\n\t\t\t\t\tserver.cancelWait();\n\t\t\t\t})\n\t\t\t\t.catch((err) => {\n\t\t\t\t\tmanualError = err instanceof Error ? err : new Error(String(err));\n\t\t\t\t\tserver.cancelWait();\n\t\t\t\t});\n\t\t\tconst result = await server.waitForCode();\n\t\t\tif (manualError) {\n\t\t\t\tthrow manualError;\n\t\t\t}\n\t\t\tif (result?.code) {\n\t\t\t\tcode = result.code;\n\t\t\t} else if (manualCode) {\n\t\t\t\tconst parsed = parseAuthorizationInput(manualCode);\n\t\t\t\tif (parsed.state && parsed.state !== state) {\n\t\t\t\t\tthrow new Error(\"State mismatch\");\n\t\t\t\t}\n\t\t\t\tcode = parsed.code;\n\t\t\t}\n\t\t\tif (!code) {\n\t\t\t\tawait manualPromise;\n\t\t\t\tif (manualError) {\n\t\t\t\t\tthrow manualError;\n\t\t\t\t}\n\t\t\t\tif (manualCode) {\n\t\t\t\t\tconst parsed = parseAuthorizationInput(manualCode);\n\t\t\t\t\tif (parsed.state && parsed.state !== state) {\n\t\t\t\t\t\tthrow new Error(\"State mismatch\");\n\t\t\t\t\t}\n\t\t\t\t\tcode = parsed.code;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tconst result = await server.waitForCode();\n\t\t\tif (result?.code) {\n\t\t\t\tcode = result.code;\n\t\t\t}\n\t\t}\n\t\tif (!code) {\n\t\t\tconst input = await options.onPrompt({\n\t\t\t\tmessage: \"Paste the authorization code (or full redirect URL):\",\n\t\t\t});\n\t\t\tconst parsed = parseAuthorizationInput(input);\n\t\t\tif (parsed.state && parsed.state !== state) {\n\t\t\t\tthrow new Error(\"State mismatch\");\n\t\t\t}\n\t\t\tcode = parsed.code;\n\t\t}\n\t\tif (!code) {\n\t\t\tthrow new Error(\"Missing authorization code\");\n\t\t}\n\t\tconst tokenResult = await exchangeAuthorizationCode(code, verifier);\n\t\tif (tokenResult.type !== \"success\") {\n\t\t\tthrow new Error(\"Token exchange failed\");\n\t\t}\n\t\tconst accountId = getAccountId(tokenResult.access);\n\t\tif (!accountId) {\n\t\t\tthrow new Error(\"Failed to extract accountId from token\");\n\t\t}\n\t\treturn {\n\t\t\taccess: tokenResult.access,\n\t\t\trefresh: tokenResult.refresh,\n\t\t\texpires: tokenResult.expires,\n\t\t\taccountId,\n\t\t};\n\t} finally {\n\t\tserver.close();\n\t}\n}\nexport async function refreshOpenAICodexToken(refreshToken: string): Promise<OAuthCredentials> {\n\tconst result = await refreshAccessToken(refreshToken);\n\tif (result.type !== \"success\") {\n\t\tthrow new Error(\"Failed to refresh OpenAI Codex token\");\n\t}\n\tconst accountId = getAccountId(result.access);\n\tif (!accountId) {\n\t\tthrow new Error(\"Failed to extract accountId from token\");\n\t}\n\treturn {\n\t\taccess: result.access,\n\t\trefresh: result.refresh,\n\t\texpires: result.expires,\n\t\taccountId,\n\t};\n}\nexport const openaiCodexOAuthProvider: OAuthProviderInterface = {\n\tid: \"openai-codex\",\n\tname: \"ChatGPT Plus/Pro (Codex Subscription)\",\n\tusesCallbackServer: true,\n\tasync login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\t\treturn loginOpenAICodex({\n\t\t\tonAuth: callbacks.onAuth,\n\t\t\tonPrompt: callbacks.onPrompt,\n\t\t\tonProgress: callbacks.onProgress,\n\t\t\tonManualCodeInput: callbacks.onManualCodeInput,\n\t\t});\n\t},\n\tasync refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n\t\treturn refreshOpenAICodexToken(credentials.refresh);\n\t},\n\tgetApiKey(credentials: OAuthCredentials): string {\n\t\treturn credentials.access;\n\t},\n};\n"]}
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
let _randomBytes = null;
|
|
2
|
+
let _http = null;
|
|
3
|
+
if (typeof process !== "undefined" && (process.versions?.node || process.versions?.bun)) {
|
|
4
|
+
import("node:crypto").then((m) => {
|
|
5
|
+
_randomBytes = m.randomBytes;
|
|
6
|
+
});
|
|
7
|
+
import("node:http").then((m) => {
|
|
8
|
+
_http = m;
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
import { generatePKCE } from "./pkce.js";
|
|
12
|
+
const CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
|
|
13
|
+
const AUTHORIZE_URL = "https://auth.openai.com/authorize";
|
|
14
|
+
const TOKEN_URL = "https://auth.openai.com/token";
|
|
15
|
+
const REDIRECT_URI = "http://localhost:8080/oauth/callback";
|
|
16
|
+
const SCOPE = "openid profile email offline_access";
|
|
17
|
+
const JWT_CLAIM_PATH = "https://api.openai.com/v1/jwt-claim";
|
|
18
|
+
const SUCCESS_HTML = `<!doctype html>
|
|
19
|
+
<html lang="en">
|
|
20
|
+
<head>
|
|
21
|
+
<meta charset="utf-8" />
|
|
22
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
23
|
+
<title>Authentication successful</title>
|
|
24
|
+
</head>
|
|
25
|
+
<body>
|
|
26
|
+
<p>Authentication successful. Return to your terminal to continue.</p>
|
|
27
|
+
</body>
|
|
28
|
+
</html>`;
|
|
29
|
+
function createState() {
|
|
30
|
+
if (!_randomBytes) {
|
|
31
|
+
throw new Error("OpenAI Codex OAuth is only available in Node.js environments");
|
|
32
|
+
}
|
|
33
|
+
return _randomBytes(16).toString("hex");
|
|
34
|
+
}
|
|
35
|
+
function parseAuthorizationInput(input) {
|
|
36
|
+
const value = input.trim();
|
|
37
|
+
if (!value)
|
|
38
|
+
return {};
|
|
39
|
+
try {
|
|
40
|
+
const url = new URL(value);
|
|
41
|
+
return {
|
|
42
|
+
code: url.searchParams.get("code") ?? undefined,
|
|
43
|
+
state: url.searchParams.get("state") ?? undefined,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
catch { }
|
|
47
|
+
if (value.includes("#")) {
|
|
48
|
+
const [code, state] = value.split("#", 2);
|
|
49
|
+
return { code, state };
|
|
50
|
+
}
|
|
51
|
+
if (value.includes("code=")) {
|
|
52
|
+
const params = new URLSearchParams(value);
|
|
53
|
+
return {
|
|
54
|
+
code: params.get("code") ?? undefined,
|
|
55
|
+
state: params.get("state") ?? undefined,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
return { code: value };
|
|
59
|
+
}
|
|
60
|
+
function decodeJwt(token) {
|
|
61
|
+
try {
|
|
62
|
+
const parts = token.split(".");
|
|
63
|
+
if (parts.length !== 3)
|
|
64
|
+
return null;
|
|
65
|
+
const payload = parts[1] ?? "";
|
|
66
|
+
const decoded = atob(payload);
|
|
67
|
+
return JSON.parse(decoded);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
async function exchangeAuthorizationCode(code, verifier, redirectUri = REDIRECT_URI) {
|
|
74
|
+
const response = await fetch(TOKEN_URL, {
|
|
75
|
+
method: "POST",
|
|
76
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
77
|
+
body: new URLSearchParams({
|
|
78
|
+
grant_type: "authorization_code",
|
|
79
|
+
client_id: CLIENT_ID,
|
|
80
|
+
code,
|
|
81
|
+
code_verifier: verifier,
|
|
82
|
+
redirect_uri: redirectUri,
|
|
83
|
+
}),
|
|
84
|
+
});
|
|
85
|
+
if (!response.ok) {
|
|
86
|
+
const text = await response.text().catch(() => "");
|
|
87
|
+
console.error("[openai-codex] code->token failed:", response.status, text);
|
|
88
|
+
return { type: "failed" };
|
|
89
|
+
}
|
|
90
|
+
const json = (await response.json());
|
|
91
|
+
if (!json.access_token || !json.refresh_token || typeof json.expires_in !== "number") {
|
|
92
|
+
console.error("[openai-codex] token response missing fields:", json);
|
|
93
|
+
return { type: "failed" };
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
type: "success",
|
|
97
|
+
access: json.access_token,
|
|
98
|
+
refresh: json.refresh_token,
|
|
99
|
+
expires: Date.now() + json.expires_in * 1000,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
async function refreshAccessToken(refreshToken) {
|
|
103
|
+
try {
|
|
104
|
+
const response = await fetch(TOKEN_URL, {
|
|
105
|
+
method: "POST",
|
|
106
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
107
|
+
body: new URLSearchParams({
|
|
108
|
+
grant_type: "refresh_token",
|
|
109
|
+
refresh_token: refreshToken,
|
|
110
|
+
client_id: CLIENT_ID,
|
|
111
|
+
}),
|
|
112
|
+
});
|
|
113
|
+
if (!response.ok) {
|
|
114
|
+
const text = await response.text().catch(() => "");
|
|
115
|
+
console.error("[openai-codex] Token refresh failed:", response.status, text);
|
|
116
|
+
return { type: "failed" };
|
|
117
|
+
}
|
|
118
|
+
const json = (await response.json());
|
|
119
|
+
if (!json.access_token || !json.refresh_token || typeof json.expires_in !== "number") {
|
|
120
|
+
console.error("[openai-codex] Token refresh response missing fields:", json);
|
|
121
|
+
return { type: "failed" };
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
type: "success",
|
|
125
|
+
access: json.access_token,
|
|
126
|
+
refresh: json.refresh_token,
|
|
127
|
+
expires: Date.now() + json.expires_in * 1000,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
console.error("[openai-codex] Token refresh error:", error);
|
|
132
|
+
return { type: "failed" };
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async function createAuthorizationFlow(originator = "pi") {
|
|
136
|
+
const { verifier, challenge } = await generatePKCE();
|
|
137
|
+
const state = createState();
|
|
138
|
+
const url = new URL(AUTHORIZE_URL);
|
|
139
|
+
url.searchParams.set("response_type", "code");
|
|
140
|
+
url.searchParams.set("client_id", CLIENT_ID);
|
|
141
|
+
url.searchParams.set("redirect_uri", REDIRECT_URI);
|
|
142
|
+
url.searchParams.set("scope", SCOPE);
|
|
143
|
+
url.searchParams.set("code_challenge", challenge);
|
|
144
|
+
url.searchParams.set("code_challenge_method", "S256");
|
|
145
|
+
url.searchParams.set("state", state);
|
|
146
|
+
url.searchParams.set("id_token_add_organizations", "true");
|
|
147
|
+
url.searchParams.set("codex_cli_simplified_flow", "true");
|
|
148
|
+
url.searchParams.set("originator", originator);
|
|
149
|
+
return { verifier, state, url: url.toString() };
|
|
150
|
+
}
|
|
151
|
+
function startLocalOAuthServer(state) {
|
|
152
|
+
if (!_http) {
|
|
153
|
+
throw new Error("OpenAI Codex OAuth is only available in Node.js environments");
|
|
154
|
+
}
|
|
155
|
+
let lastCode = null;
|
|
156
|
+
let cancelled = false;
|
|
157
|
+
const server = _http.createServer((req, res) => {
|
|
158
|
+
try {
|
|
159
|
+
const url = new URL(req.url || "", "http://localhost:1455");
|
|
160
|
+
if (url.pathname !== "/auth/callback") {
|
|
161
|
+
res.statusCode = 404;
|
|
162
|
+
res.end("Not found");
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (url.searchParams.get("state") !== state) {
|
|
166
|
+
res.statusCode = 400;
|
|
167
|
+
res.end("State mismatch");
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const code = url.searchParams.get("code");
|
|
171
|
+
if (!code) {
|
|
172
|
+
res.statusCode = 400;
|
|
173
|
+
res.end("Missing authorization code");
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
res.statusCode = 200;
|
|
177
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
178
|
+
res.end(SUCCESS_HTML);
|
|
179
|
+
lastCode = code;
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
res.statusCode = 500;
|
|
183
|
+
res.end("Internal error");
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
return new Promise((resolve) => {
|
|
187
|
+
server
|
|
188
|
+
.listen(1455, "127.0.0.1", () => {
|
|
189
|
+
resolve({
|
|
190
|
+
close: () => server.close(),
|
|
191
|
+
cancelWait: () => {
|
|
192
|
+
cancelled = true;
|
|
193
|
+
},
|
|
194
|
+
waitForCode: async () => {
|
|
195
|
+
const sleep = () => new Promise((r) => setTimeout(r, 100));
|
|
196
|
+
for (let i = 0; i < 600; i += 1) {
|
|
197
|
+
if (lastCode)
|
|
198
|
+
return { code: lastCode };
|
|
199
|
+
if (cancelled)
|
|
200
|
+
return null;
|
|
201
|
+
await sleep();
|
|
202
|
+
}
|
|
203
|
+
return null;
|
|
204
|
+
},
|
|
205
|
+
});
|
|
206
|
+
})
|
|
207
|
+
.on("error", (err) => {
|
|
208
|
+
console.error("[openai-codex] Failed to bind http://localhost:1455 (", err.code, ") Falling back to manual paste.");
|
|
209
|
+
resolve({
|
|
210
|
+
close: () => {
|
|
211
|
+
try {
|
|
212
|
+
server.close();
|
|
213
|
+
}
|
|
214
|
+
catch { }
|
|
215
|
+
},
|
|
216
|
+
cancelWait: () => { },
|
|
217
|
+
waitForCode: async () => null,
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
function getAccountId(accessToken) {
|
|
223
|
+
const payload = decodeJwt(accessToken);
|
|
224
|
+
const auth = payload?.[JWT_CLAIM_PATH];
|
|
225
|
+
const accountId = auth?.chatgpt_account_id;
|
|
226
|
+
return typeof accountId === "string" && accountId.length > 0 ? accountId : null;
|
|
227
|
+
}
|
|
228
|
+
export async function loginOpenAICodex(options) {
|
|
229
|
+
const { verifier, state, url } = await createAuthorizationFlow(options.originator);
|
|
230
|
+
const server = await startLocalOAuthServer(state);
|
|
231
|
+
options.onAuth({ url, instructions: "A browser window should open. Complete login to finish." });
|
|
232
|
+
let code;
|
|
233
|
+
try {
|
|
234
|
+
if (options.onManualCodeInput) {
|
|
235
|
+
let manualCode;
|
|
236
|
+
let manualError;
|
|
237
|
+
const manualPromise = options
|
|
238
|
+
.onManualCodeInput()
|
|
239
|
+
.then((input) => {
|
|
240
|
+
manualCode = input;
|
|
241
|
+
server.cancelWait();
|
|
242
|
+
})
|
|
243
|
+
.catch((err) => {
|
|
244
|
+
manualError = err instanceof Error ? err : new Error(String(err));
|
|
245
|
+
server.cancelWait();
|
|
246
|
+
});
|
|
247
|
+
const result = await server.waitForCode();
|
|
248
|
+
if (manualError) {
|
|
249
|
+
throw manualError;
|
|
250
|
+
}
|
|
251
|
+
if (result?.code) {
|
|
252
|
+
code = result.code;
|
|
253
|
+
}
|
|
254
|
+
else if (manualCode) {
|
|
255
|
+
const parsed = parseAuthorizationInput(manualCode);
|
|
256
|
+
if (parsed.state && parsed.state !== state) {
|
|
257
|
+
throw new Error("State mismatch");
|
|
258
|
+
}
|
|
259
|
+
code = parsed.code;
|
|
260
|
+
}
|
|
261
|
+
if (!code) {
|
|
262
|
+
await manualPromise;
|
|
263
|
+
if (manualError) {
|
|
264
|
+
throw manualError;
|
|
265
|
+
}
|
|
266
|
+
if (manualCode) {
|
|
267
|
+
const parsed = parseAuthorizationInput(manualCode);
|
|
268
|
+
if (parsed.state && parsed.state !== state) {
|
|
269
|
+
throw new Error("State mismatch");
|
|
270
|
+
}
|
|
271
|
+
code = parsed.code;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
const result = await server.waitForCode();
|
|
277
|
+
if (result?.code) {
|
|
278
|
+
code = result.code;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
if (!code) {
|
|
282
|
+
const input = await options.onPrompt({
|
|
283
|
+
message: "Paste the authorization code (or full redirect URL):",
|
|
284
|
+
});
|
|
285
|
+
const parsed = parseAuthorizationInput(input);
|
|
286
|
+
if (parsed.state && parsed.state !== state) {
|
|
287
|
+
throw new Error("State mismatch");
|
|
288
|
+
}
|
|
289
|
+
code = parsed.code;
|
|
290
|
+
}
|
|
291
|
+
if (!code) {
|
|
292
|
+
throw new Error("Missing authorization code");
|
|
293
|
+
}
|
|
294
|
+
const tokenResult = await exchangeAuthorizationCode(code, verifier);
|
|
295
|
+
if (tokenResult.type !== "success") {
|
|
296
|
+
throw new Error("Token exchange failed");
|
|
297
|
+
}
|
|
298
|
+
const accountId = getAccountId(tokenResult.access);
|
|
299
|
+
if (!accountId) {
|
|
300
|
+
throw new Error("Failed to extract accountId from token");
|
|
301
|
+
}
|
|
302
|
+
return {
|
|
303
|
+
access: tokenResult.access,
|
|
304
|
+
refresh: tokenResult.refresh,
|
|
305
|
+
expires: tokenResult.expires,
|
|
306
|
+
accountId,
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
finally {
|
|
310
|
+
server.close();
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
export async function refreshOpenAICodexToken(refreshToken) {
|
|
314
|
+
const result = await refreshAccessToken(refreshToken);
|
|
315
|
+
if (result.type !== "success") {
|
|
316
|
+
throw new Error("Failed to refresh OpenAI Codex token");
|
|
317
|
+
}
|
|
318
|
+
const accountId = getAccountId(result.access);
|
|
319
|
+
if (!accountId) {
|
|
320
|
+
throw new Error("Failed to extract accountId from token");
|
|
321
|
+
}
|
|
322
|
+
return {
|
|
323
|
+
access: result.access,
|
|
324
|
+
refresh: result.refresh,
|
|
325
|
+
expires: result.expires,
|
|
326
|
+
accountId,
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
export const openaiCodexOAuthProvider = {
|
|
330
|
+
id: "openai-codex",
|
|
331
|
+
name: "ChatGPT Plus/Pro (Codex Subscription)",
|
|
332
|
+
usesCallbackServer: true,
|
|
333
|
+
async login(callbacks) {
|
|
334
|
+
return loginOpenAICodex({
|
|
335
|
+
onAuth: callbacks.onAuth,
|
|
336
|
+
onPrompt: callbacks.onPrompt,
|
|
337
|
+
onProgress: callbacks.onProgress,
|
|
338
|
+
onManualCodeInput: callbacks.onManualCodeInput,
|
|
339
|
+
});
|
|
340
|
+
},
|
|
341
|
+
async refreshToken(credentials) {
|
|
342
|
+
return refreshOpenAICodexToken(credentials.refresh);
|
|
343
|
+
},
|
|
344
|
+
getApiKey(credentials) {
|
|
345
|
+
return credentials.access;
|
|
346
|
+
},
|
|
347
|
+
};
|
|
348
|
+
//# sourceMappingURL=openai-codex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-codex.js","sourceRoot":"","sources":["../../../src/utils/oauth/openai-codex.ts"],"names":[],"mappings":"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","sourcesContent":["let _randomBytes: typeof import(\"node:crypto\").randomBytes | null = null;\nlet _http: typeof import(\"node:http\") | null = null;\nif (typeof process !== \"undefined\" && (process.versions?.node || process.versions?.bun)) {\n\timport(\"node:crypto\").then((m) => {\n\t\t_randomBytes = m.randomBytes;\n\t});\n\timport(\"node:http\").then((m) => {\n\t\t_http = m;\n\t});\n}\n\nimport { generatePKCE } from \"./pkce.js\";\nimport type { OAuthCredentials, OAuthLoginCallbacks, OAuthPrompt, OAuthProviderInterface } from \"./types.js\";\n\nconst CLIENT_ID = \"app_EMoamEEZ73f0CkXaXp7hrann\";\nconst AUTHORIZE_URL = \"https://auth.openai.com/authorize\";\nconst TOKEN_URL = \"https://auth.openai.com/token\";\nconst REDIRECT_URI = \"http://localhost:8080/oauth/callback\";\nconst SCOPE = \"openid profile email offline_access\";\nconst JWT_CLAIM_PATH = \"https://api.openai.com/v1/jwt-claim\";\nconst SUCCESS_HTML = `<!doctype html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <title>Authentication successful</title>\n</head>\n<body>\n <p>Authentication successful. Return to your terminal to continue.</p>\n</body>\n</html>`;\ntype TokenSuccess = { type: \"success\"; access: string; refresh: string; expires: number };\ntype TokenFailure = { type: \"failed\" };\ntype TokenResult = TokenSuccess | TokenFailure;\ntype JwtPayload = {\n\t[JWT_CLAIM_PATH]?: {\n\t\tchatgpt_account_id?: string;\n\t};\n\t[key: string]: unknown;\n};\nfunction createState(): string {\n\tif (!_randomBytes) {\n\t\tthrow new Error(\"OpenAI Codex OAuth is only available in Node.js environments\");\n\t}\n\treturn _randomBytes(16).toString(\"hex\");\n}\nfunction parseAuthorizationInput(input: string): { code?: string; state?: string } {\n\tconst value = input.trim();\n\tif (!value) return {};\n\ttry {\n\t\tconst url = new URL(value);\n\t\treturn {\n\t\t\tcode: url.searchParams.get(\"code\") ?? undefined,\n\t\t\tstate: url.searchParams.get(\"state\") ?? undefined,\n\t\t};\n\t} catch {}\n\tif (value.includes(\"#\")) {\n\t\tconst [code, state] = value.split(\"#\", 2);\n\t\treturn { code, state };\n\t}\n\tif (value.includes(\"code=\")) {\n\t\tconst params = new URLSearchParams(value);\n\t\treturn {\n\t\t\tcode: params.get(\"code\") ?? undefined,\n\t\t\tstate: params.get(\"state\") ?? undefined,\n\t\t};\n\t}\n\treturn { code: value };\n}\nfunction decodeJwt(token: string): JwtPayload | null {\n\ttry {\n\t\tconst parts = token.split(\".\");\n\t\tif (parts.length !== 3) return null;\n\t\tconst payload = parts[1] ?? \"\";\n\t\tconst decoded = atob(payload);\n\t\treturn JSON.parse(decoded) as JwtPayload;\n\t} catch {\n\t\treturn null;\n\t}\n}\nasync function exchangeAuthorizationCode(\n\tcode: string,\n\tverifier: string,\n\tredirectUri: string = REDIRECT_URI,\n): Promise<TokenResult> {\n\tconst response = await fetch(TOKEN_URL, {\n\t\tmethod: \"POST\",\n\t\theaders: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n\t\tbody: new URLSearchParams({\n\t\t\tgrant_type: \"authorization_code\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\tcode,\n\t\t\tcode_verifier: verifier,\n\t\t\tredirect_uri: redirectUri,\n\t\t}),\n\t});\n\tif (!response.ok) {\n\t\tconst text = await response.text().catch(() => \"\");\n\t\tconsole.error(\"[openai-codex] code->token failed:\", response.status, text);\n\t\treturn { type: \"failed\" };\n\t}\n\tconst json = (await response.json()) as {\n\t\taccess_token?: string;\n\t\trefresh_token?: string;\n\t\texpires_in?: number;\n\t};\n\tif (!json.access_token || !json.refresh_token || typeof json.expires_in !== \"number\") {\n\t\tconsole.error(\"[openai-codex] token response missing fields:\", json);\n\t\treturn { type: \"failed\" };\n\t}\n\treturn {\n\t\ttype: \"success\",\n\t\taccess: json.access_token,\n\t\trefresh: json.refresh_token,\n\t\texpires: Date.now() + json.expires_in * 1000,\n\t};\n}\nasync function refreshAccessToken(refreshToken: string): Promise<TokenResult> {\n\ttry {\n\t\tconst response = await fetch(TOKEN_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tgrant_type: \"refresh_token\",\n\t\t\t\trefresh_token: refreshToken,\n\t\t\t\tclient_id: CLIENT_ID,\n\t\t\t}),\n\t\t});\n\t\tif (!response.ok) {\n\t\t\tconst text = await response.text().catch(() => \"\");\n\t\t\tconsole.error(\"[openai-codex] Token refresh failed:\", response.status, text);\n\t\t\treturn { type: \"failed\" };\n\t\t}\n\t\tconst json = (await response.json()) as {\n\t\t\taccess_token?: string;\n\t\t\trefresh_token?: string;\n\t\t\texpires_in?: number;\n\t\t};\n\t\tif (!json.access_token || !json.refresh_token || typeof json.expires_in !== \"number\") {\n\t\t\tconsole.error(\"[openai-codex] Token refresh response missing fields:\", json);\n\t\t\treturn { type: \"failed\" };\n\t\t}\n\t\treturn {\n\t\t\ttype: \"success\",\n\t\t\taccess: json.access_token,\n\t\t\trefresh: json.refresh_token,\n\t\t\texpires: Date.now() + json.expires_in * 1000,\n\t\t};\n\t} catch (error) {\n\t\tconsole.error(\"[openai-codex] Token refresh error:\", error);\n\t\treturn { type: \"failed\" };\n\t}\n}\nasync function createAuthorizationFlow(\n\toriginator: string = \"pi\",\n): Promise<{ verifier: string; state: string; url: string }> {\n\tconst { verifier, challenge } = await generatePKCE();\n\tconst state = createState();\n\tconst url = new URL(AUTHORIZE_URL);\n\turl.searchParams.set(\"response_type\", \"code\");\n\turl.searchParams.set(\"client_id\", CLIENT_ID);\n\turl.searchParams.set(\"redirect_uri\", REDIRECT_URI);\n\turl.searchParams.set(\"scope\", SCOPE);\n\turl.searchParams.set(\"code_challenge\", challenge);\n\turl.searchParams.set(\"code_challenge_method\", \"S256\");\n\turl.searchParams.set(\"state\", state);\n\turl.searchParams.set(\"id_token_add_organizations\", \"true\");\n\turl.searchParams.set(\"codex_cli_simplified_flow\", \"true\");\n\turl.searchParams.set(\"originator\", originator);\n\treturn { verifier, state, url: url.toString() };\n}\ntype OAuthServerInfo = {\n\tclose: () => void;\n\tcancelWait: () => void;\n\twaitForCode: () => Promise<{ code: string } | null>;\n};\nfunction startLocalOAuthServer(state: string): Promise<OAuthServerInfo> {\n\tif (!_http) {\n\t\tthrow new Error(\"OpenAI Codex OAuth is only available in Node.js environments\");\n\t}\n\tlet lastCode: string | null = null;\n\tlet cancelled = false;\n\tconst server = _http.createServer((req, res) => {\n\t\ttry {\n\t\t\tconst url = new URL(req.url || \"\", \"http://localhost:1455\");\n\t\t\tif (url.pathname !== \"/auth/callback\") {\n\t\t\t\tres.statusCode = 404;\n\t\t\t\tres.end(\"Not found\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (url.searchParams.get(\"state\") !== state) {\n\t\t\t\tres.statusCode = 400;\n\t\t\t\tres.end(\"State mismatch\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst code = url.searchParams.get(\"code\");\n\t\t\tif (!code) {\n\t\t\t\tres.statusCode = 400;\n\t\t\t\tres.end(\"Missing authorization code\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tres.statusCode = 200;\n\t\t\tres.setHeader(\"Content-Type\", \"text/html; charset=utf-8\");\n\t\t\tres.end(SUCCESS_HTML);\n\t\t\tlastCode = code;\n\t\t} catch {\n\t\t\tres.statusCode = 500;\n\t\t\tres.end(\"Internal error\");\n\t\t}\n\t});\n\treturn new Promise((resolve) => {\n\t\tserver\n\t\t\t.listen(1455, \"127.0.0.1\", () => {\n\t\t\t\tresolve({\n\t\t\t\t\tclose: () => server.close(),\n\t\t\t\t\tcancelWait: () => {\n\t\t\t\t\t\tcancelled = true;\n\t\t\t\t\t},\n\t\t\t\t\twaitForCode: async () => {\n\t\t\t\t\t\tconst sleep = () => new Promise((r) => setTimeout(r, 100));\n\t\t\t\t\t\tfor (let i = 0; i < 600; i += 1) {\n\t\t\t\t\t\t\tif (lastCode) return { code: lastCode };\n\t\t\t\t\t\t\tif (cancelled) return null;\n\t\t\t\t\t\t\tawait sleep();\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t})\n\t\t\t.on(\"error\", (err: NodeJS.ErrnoException) => {\n\t\t\t\tconsole.error(\n\t\t\t\t\t\"[openai-codex] Failed to bind http://localhost:1455 (\",\n\t\t\t\t\terr.code,\n\t\t\t\t\t\") Falling back to manual paste.\",\n\t\t\t\t);\n\t\t\t\tresolve({\n\t\t\t\t\tclose: () => {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tserver.close();\n\t\t\t\t\t\t} catch {}\n\t\t\t\t\t},\n\t\t\t\t\tcancelWait: () => {},\n\t\t\t\t\twaitForCode: async () => null,\n\t\t\t\t});\n\t\t\t});\n\t});\n}\nfunction getAccountId(accessToken: string): string | null {\n\tconst payload = decodeJwt(accessToken);\n\tconst auth = payload?.[JWT_CLAIM_PATH];\n\tconst accountId = auth?.chatgpt_account_id;\n\treturn typeof accountId === \"string\" && accountId.length > 0 ? accountId : null;\n}\nexport async function loginOpenAICodex(options: {\n\tonAuth: (info: { url: string; instructions?: string }) => void;\n\tonPrompt: (prompt: OAuthPrompt) => Promise<string>;\n\tonProgress?: (message: string) => void;\n\tonManualCodeInput?: () => Promise<string>;\n\toriginator?: string;\n}): Promise<OAuthCredentials> {\n\tconst { verifier, state, url } = await createAuthorizationFlow(options.originator);\n\tconst server = await startLocalOAuthServer(state);\n\toptions.onAuth({ url, instructions: \"A browser window should open. Complete login to finish.\" });\n\tlet code: string | undefined;\n\ttry {\n\t\tif (options.onManualCodeInput) {\n\t\t\tlet manualCode: string | undefined;\n\t\t\tlet manualError: Error | undefined;\n\t\t\tconst manualPromise = options\n\t\t\t\t.onManualCodeInput()\n\t\t\t\t.then((input) => {\n\t\t\t\t\tmanualCode = input;\n\t\t\t\t\tserver.cancelWait();\n\t\t\t\t})\n\t\t\t\t.catch((err) => {\n\t\t\t\t\tmanualError = err instanceof Error ? err : new Error(String(err));\n\t\t\t\t\tserver.cancelWait();\n\t\t\t\t});\n\t\t\tconst result = await server.waitForCode();\n\t\t\tif (manualError) {\n\t\t\t\tthrow manualError;\n\t\t\t}\n\t\t\tif (result?.code) {\n\t\t\t\tcode = result.code;\n\t\t\t} else if (manualCode) {\n\t\t\t\tconst parsed = parseAuthorizationInput(manualCode);\n\t\t\t\tif (parsed.state && parsed.state !== state) {\n\t\t\t\t\tthrow new Error(\"State mismatch\");\n\t\t\t\t}\n\t\t\t\tcode = parsed.code;\n\t\t\t}\n\t\t\tif (!code) {\n\t\t\t\tawait manualPromise;\n\t\t\t\tif (manualError) {\n\t\t\t\t\tthrow manualError;\n\t\t\t\t}\n\t\t\t\tif (manualCode) {\n\t\t\t\t\tconst parsed = parseAuthorizationInput(manualCode);\n\t\t\t\t\tif (parsed.state && parsed.state !== state) {\n\t\t\t\t\t\tthrow new Error(\"State mismatch\");\n\t\t\t\t\t}\n\t\t\t\t\tcode = parsed.code;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tconst result = await server.waitForCode();\n\t\t\tif (result?.code) {\n\t\t\t\tcode = result.code;\n\t\t\t}\n\t\t}\n\t\tif (!code) {\n\t\t\tconst input = await options.onPrompt({\n\t\t\t\tmessage: \"Paste the authorization code (or full redirect URL):\",\n\t\t\t});\n\t\t\tconst parsed = parseAuthorizationInput(input);\n\t\t\tif (parsed.state && parsed.state !== state) {\n\t\t\t\tthrow new Error(\"State mismatch\");\n\t\t\t}\n\t\t\tcode = parsed.code;\n\t\t}\n\t\tif (!code) {\n\t\t\tthrow new Error(\"Missing authorization code\");\n\t\t}\n\t\tconst tokenResult = await exchangeAuthorizationCode(code, verifier);\n\t\tif (tokenResult.type !== \"success\") {\n\t\t\tthrow new Error(\"Token exchange failed\");\n\t\t}\n\t\tconst accountId = getAccountId(tokenResult.access);\n\t\tif (!accountId) {\n\t\t\tthrow new Error(\"Failed to extract accountId from token\");\n\t\t}\n\t\treturn {\n\t\t\taccess: tokenResult.access,\n\t\t\trefresh: tokenResult.refresh,\n\t\t\texpires: tokenResult.expires,\n\t\t\taccountId,\n\t\t};\n\t} finally {\n\t\tserver.close();\n\t}\n}\nexport async function refreshOpenAICodexToken(refreshToken: string): Promise<OAuthCredentials> {\n\tconst result = await refreshAccessToken(refreshToken);\n\tif (result.type !== \"success\") {\n\t\tthrow new Error(\"Failed to refresh OpenAI Codex token\");\n\t}\n\tconst accountId = getAccountId(result.access);\n\tif (!accountId) {\n\t\tthrow new Error(\"Failed to extract accountId from token\");\n\t}\n\treturn {\n\t\taccess: result.access,\n\t\trefresh: result.refresh,\n\t\texpires: result.expires,\n\t\taccountId,\n\t};\n}\nexport const openaiCodexOAuthProvider: OAuthProviderInterface = {\n\tid: \"openai-codex\",\n\tname: \"ChatGPT Plus/Pro (Codex Subscription)\",\n\tusesCallbackServer: true,\n\tasync login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\t\treturn loginOpenAICodex({\n\t\t\tonAuth: callbacks.onAuth,\n\t\t\tonPrompt: callbacks.onPrompt,\n\t\t\tonProgress: callbacks.onProgress,\n\t\t\tonManualCodeInput: callbacks.onManualCodeInput,\n\t\t});\n\t},\n\tasync refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n\t\treturn refreshOpenAICodexToken(credentials.refresh);\n\t},\n\tgetApiKey(credentials: OAuthCredentials): string {\n\t\treturn credentials.access;\n\t},\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pkce.d.ts","sourceRoot":"","sources":["../../../src/utils/oauth/pkce.ts"],"names":[],"mappings":"AAOA,wBAAsB,YAAY,IAAI,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CASrF","sourcesContent":["function base64urlEncode(bytes: Uint8Array): string {\n\tlet binary = \"\";\n\tfor (const byte of bytes) {\n\t\tbinary += String.fromCharCode(byte);\n\t}\n\treturn btoa(binary).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=/g, \"\");\n}\nexport async function generatePKCE(): Promise<{ verifier: string; challenge: string }> {\n\tconst verifierBytes = new Uint8Array(32);\n\tcrypto.getRandomValues(verifierBytes);\n\tconst verifier = base64urlEncode(verifierBytes);\n\tconst encoder = new TextEncoder();\n\tconst data = encoder.encode(verifier);\n\tconst hashBuffer = await crypto.subtle.digest(\"SHA-256\", data);\n\tconst challenge = base64urlEncode(new Uint8Array(hashBuffer));\n\treturn { verifier, challenge };\n}\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
function base64urlEncode(bytes) {
|
|
2
|
+
let binary = "";
|
|
3
|
+
for (const byte of bytes) {
|
|
4
|
+
binary += String.fromCharCode(byte);
|
|
5
|
+
}
|
|
6
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
7
|
+
}
|
|
8
|
+
export async function generatePKCE() {
|
|
9
|
+
const verifierBytes = new Uint8Array(32);
|
|
10
|
+
crypto.getRandomValues(verifierBytes);
|
|
11
|
+
const verifier = base64urlEncode(verifierBytes);
|
|
12
|
+
const encoder = new TextEncoder();
|
|
13
|
+
const data = encoder.encode(verifier);
|
|
14
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
|
|
15
|
+
const challenge = base64urlEncode(new Uint8Array(hashBuffer));
|
|
16
|
+
return { verifier, challenge };
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=pkce.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pkce.js","sourceRoot":"","sources":["../../../src/utils/oauth/pkce.ts"],"names":[],"mappings":"AAAA,SAAS,eAAe,CAAC,KAAiB,EAAU;IACnD,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QAC1B,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;AAAA,CAC9E;AACD,MAAM,CAAC,KAAK,UAAU,YAAY,GAAqD;IACtF,MAAM,aAAa,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;IACzC,MAAM,CAAC,eAAe,CAAC,aAAa,CAAC,CAAC;IACtC,MAAM,QAAQ,GAAG,eAAe,CAAC,aAAa,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACtC,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAC/D,MAAM,SAAS,GAAG,eAAe,CAAC,IAAI,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC;IAC9D,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AAAA,CAC/B","sourcesContent":["function base64urlEncode(bytes: Uint8Array): string {\n\tlet binary = \"\";\n\tfor (const byte of bytes) {\n\t\tbinary += String.fromCharCode(byte);\n\t}\n\treturn btoa(binary).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=/g, \"\");\n}\nexport async function generatePKCE(): Promise<{ verifier: string; challenge: string }> {\n\tconst verifierBytes = new Uint8Array(32);\n\tcrypto.getRandomValues(verifierBytes);\n\tconst verifier = base64urlEncode(verifierBytes);\n\tconst encoder = new TextEncoder();\n\tconst data = encoder.encode(verifier);\n\tconst hashBuffer = await crypto.subtle.digest(\"SHA-256\", data);\n\tconst challenge = base64urlEncode(new Uint8Array(hashBuffer));\n\treturn { verifier, challenge };\n}\n"]}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Api, Model } from "../../types.js";
|
|
2
|
+
export type OAuthCredentials = {
|
|
3
|
+
refresh: string;
|
|
4
|
+
access: string;
|
|
5
|
+
expires: number;
|
|
6
|
+
[key: string]: unknown;
|
|
7
|
+
};
|
|
8
|
+
export type OAuthProviderId = string;
|
|
9
|
+
export type OAuthProvider = OAuthProviderId;
|
|
10
|
+
export type OAuthPrompt = {
|
|
11
|
+
message: string;
|
|
12
|
+
placeholder?: string;
|
|
13
|
+
allowEmpty?: boolean;
|
|
14
|
+
};
|
|
15
|
+
export type OAuthAuthInfo = {
|
|
16
|
+
url: string;
|
|
17
|
+
instructions?: string;
|
|
18
|
+
};
|
|
19
|
+
export interface OAuthLoginCallbacks {
|
|
20
|
+
onAuth: (info: OAuthAuthInfo) => void;
|
|
21
|
+
onPrompt: (prompt: OAuthPrompt) => Promise<string>;
|
|
22
|
+
onProgress?: (message: string) => void;
|
|
23
|
+
onManualCodeInput?: () => Promise<string>;
|
|
24
|
+
signal?: AbortSignal;
|
|
25
|
+
}
|
|
26
|
+
export interface OAuthProviderInterface {
|
|
27
|
+
readonly id: OAuthProviderId;
|
|
28
|
+
readonly name: string;
|
|
29
|
+
login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials>;
|
|
30
|
+
usesCallbackServer?: boolean;
|
|
31
|
+
refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials>;
|
|
32
|
+
getApiKey(credentials: OAuthCredentials): string;
|
|
33
|
+
modifyModels?(models: Model<Api>[], credentials: OAuthCredentials): Model<Api>[];
|
|
34
|
+
}
|
|
35
|
+
export interface OAuthProviderInfo {
|
|
36
|
+
id: OAuthProviderId;
|
|
37
|
+
name: string;
|
|
38
|
+
available: boolean;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/utils/oauth/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACjD,MAAM,MAAM,gBAAgB,GAAG;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB,CAAC;AACF,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC;AACrC,MAAM,MAAM,aAAa,GAAG,eAAe,CAAC;AAC5C,MAAM,MAAM,WAAW,GAAG;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AACF,MAAM,MAAM,aAAa,GAAG;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AACF,MAAM,WAAW,mBAAmB;IACnC,MAAM,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;IACtC,QAAQ,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACnD,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1C,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AACD,MAAM,WAAW,sBAAsB;IACtC,QAAQ,CAAC,EAAE,EAAE,eAAe,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,SAAS,EAAE,mBAAmB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACjE,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,YAAY,CAAC,WAAW,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACvE,SAAS,CAAC,WAAW,EAAE,gBAAgB,GAAG,MAAM,CAAC;IACjD,YAAY,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,WAAW,EAAE,gBAAgB,GAAG,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;CACjF;AACD,MAAM,WAAW,iBAAiB;IACjC,EAAE,EAAE,eAAe,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;CACnB","sourcesContent":["import type { Api, Model } from \"../../types.js\";\nexport type OAuthCredentials = {\n\trefresh: string;\n\taccess: string;\n\texpires: number;\n\t[key: string]: unknown;\n};\nexport type OAuthProviderId = string;\nexport type OAuthProvider = OAuthProviderId;\nexport type OAuthPrompt = {\n\tmessage: string;\n\tplaceholder?: string;\n\tallowEmpty?: boolean;\n};\nexport type OAuthAuthInfo = {\n\turl: string;\n\tinstructions?: string;\n};\nexport interface OAuthLoginCallbacks {\n\tonAuth: (info: OAuthAuthInfo) => void;\n\tonPrompt: (prompt: OAuthPrompt) => Promise<string>;\n\tonProgress?: (message: string) => void;\n\tonManualCodeInput?: () => Promise<string>;\n\tsignal?: AbortSignal;\n}\nexport interface OAuthProviderInterface {\n\treadonly id: OAuthProviderId;\n\treadonly name: string;\n\tlogin(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials>;\n\tusesCallbackServer?: boolean;\n\trefreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials>;\n\tgetApiKey(credentials: OAuthCredentials): string;\n\tmodifyModels?(models: Model<Api>[], credentials: OAuthCredentials): Model<Api>[];\n}\nexport interface OAuthProviderInfo {\n\tid: OAuthProviderId;\n\tname: string;\n\tavailable: boolean;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/utils/oauth/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Api, Model } from \"../../types.js\";\nexport type OAuthCredentials = {\n\trefresh: string;\n\taccess: string;\n\texpires: number;\n\t[key: string]: unknown;\n};\nexport type OAuthProviderId = string;\nexport type OAuthProvider = OAuthProviderId;\nexport type OAuthPrompt = {\n\tmessage: string;\n\tplaceholder?: string;\n\tallowEmpty?: boolean;\n};\nexport type OAuthAuthInfo = {\n\turl: string;\n\tinstructions?: string;\n};\nexport interface OAuthLoginCallbacks {\n\tonAuth: (info: OAuthAuthInfo) => void;\n\tonPrompt: (prompt: OAuthPrompt) => Promise<string>;\n\tonProgress?: (message: string) => void;\n\tonManualCodeInput?: () => Promise<string>;\n\tsignal?: AbortSignal;\n}\nexport interface OAuthProviderInterface {\n\treadonly id: OAuthProviderId;\n\treadonly name: string;\n\tlogin(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials>;\n\tusesCallbackServer?: boolean;\n\trefreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials>;\n\tgetApiKey(credentials: OAuthCredentials): string;\n\tmodifyModels?(models: Model<Api>[], credentials: OAuthCredentials): Model<Api>[];\n}\nexport interface OAuthProviderInfo {\n\tid: OAuthProviderId;\n\tname: string;\n\tavailable: boolean;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overflow.d.ts","sourceRoot":"","sources":["../../src/utils/overflow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAqBpD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,gBAAgB,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAgB5F;AACD,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAE9C","sourcesContent":["import type { AssistantMessage } from \"../types.js\";\n\nconst OVERFLOW_PATTERNS = [\n\t/prompt is too long/i,\n\t/input is too long for requested model/i,\n\t/exceeds the context window/i,\n\t/input token count.*exceeds the maximum/i,\n\t/maximum prompt length is \\d+/i,\n\t/reduce the length of the messages/i,\n\t/maximum context length is \\d+ tokens/i,\n\t/exceeds the limit of \\d+/i,\n\t/exceeds the available context size/i,\n\t/greater than the context length/i,\n\t/context window exceeds limit/i,\n\t/exceeded model token limit/i,\n\t/too large for model with \\d+ maximum context length/i,\n\t/model_context_window_exceeded/i,\n\t/context[_ ]length[_ ]exceeded/i,\n\t/too many tokens/i,\n\t/token limit exceeded/i,\n];\nexport function isContextOverflow(message: AssistantMessage, contextWindow?: number): boolean {\n\tif (message.stopReason === \"error\" && message.errorMessage) {\n\t\tif (OVERFLOW_PATTERNS.some((p) => p.test(message.errorMessage!))) {\n\t\t\treturn true;\n\t\t}\n\t\tif (/^4(00|13)\\s*(status code)?\\s*\\(no body\\)/i.test(message.errorMessage)) {\n\t\t\treturn true;\n\t\t}\n\t}\n\tif (contextWindow && message.stopReason === \"stop\") {\n\t\tconst inputTokens = message.usage.input + message.usage.cacheRead;\n\t\tif (inputTokens > contextWindow) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\nexport function getOverflowPatterns(): RegExp[] {\n\treturn [...OVERFLOW_PATTERNS];\n}\n"]}
|