@mariozechner/pi-ai 0.58.1 → 0.58.3
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 +23 -0
- package/dist/models.generated.d.ts +35 -1
- package/dist/models.generated.d.ts.map +1 -1
- package/dist/models.generated.js +39 -5
- package/dist/models.generated.js.map +1 -1
- package/dist/utils/oauth/anthropic.d.ts.map +1 -1
- package/dist/utils/oauth/anthropic.js +1 -6
- package/dist/utils/oauth/anthropic.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../../src/utils/oauth/anthropic.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAuB,WAAW,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAsO7G;;GAEG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE;IAC7C,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;CAC1C,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA+G5B;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAgC3F;AAED,eAAO,MAAM,sBAAsB,EAAE,sBAqBpC,CAAC","sourcesContent":["/**\n * Anthropic OAuth flow (Claude Pro/Max)\n *\n * NOTE: This module uses Node.js http.createServer for the OAuth callback server.\n * It is only intended for CLI use, not browser environments.\n */\n\nimport type { Server } from \"node:http\";\nimport { generatePKCE } from \"./pkce.js\";\nimport type { OAuthCredentials, OAuthLoginCallbacks, OAuthPrompt, OAuthProviderInterface } from \"./types.js\";\n\ntype CallbackServerInfo = {\n\tserver: Server;\n\tredirectUri: string;\n\tcancelWait: () => void;\n\twaitForCode: () => Promise<{ code: string; state: string } | null>;\n};\n\ntype NodeApis = {\n\tcreateServer: typeof import(\"node:http\").createServer;\n};\n\nlet nodeApis: NodeApis | null = null;\nlet nodeApisPromise: Promise<NodeApis> | null = null;\n\nconst decode = (s: string) => atob(s);\nconst CLIENT_ID = decode(\"OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl\");\nconst AUTHORIZE_URL = \"https://claude.ai/oauth/authorize\";\nconst TOKEN_URL = \"https://platform.claude.com/v1/oauth/token\";\nconst MANUAL_REDIRECT_URI = \"https://platform.claude.com/oauth/code/callback\";\nconst CALLBACK_HOST = \"127.0.0.1\";\nconst CALLBACK_PORT = 53692;\nconst CALLBACK_PATH = \"/callback\";\nconst REDIRECT_URI = `http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`;\nconst SCOPES =\n\t\"org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload\";\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>`;\n\nasync function getNodeApis(): Promise<NodeApis> {\n\tif (nodeApis) return nodeApis;\n\tif (!nodeApisPromise) {\n\t\tif (typeof process === \"undefined\" || (!process.versions?.node && !process.versions?.bun)) {\n\t\t\tthrow new Error(\"Anthropic OAuth is only available in Node.js environments\");\n\t\t}\n\t\tnodeApisPromise = import(\"node:http\").then((httpModule) => ({\n\t\t\tcreateServer: httpModule.createServer,\n\t\t}));\n\t}\n\tnodeApis = await nodeApisPromise;\n\treturn nodeApis;\n}\n\nfunction parseAuthorizationInput(input: string): { code?: string; state?: string } {\n\tconst value = input.trim();\n\tif (!value) return {};\n\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\t\t// not a URL\n\t}\n\n\tif (value.includes(\"#\")) {\n\t\tconst [code, state] = value.split(\"#\", 2);\n\t\treturn { code, state };\n\t}\n\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\n\treturn { code: value };\n}\n\nfunction formatErrorDetails(error: unknown): string {\n\tif (error instanceof Error) {\n\t\tconst details: string[] = [`${error.name}: ${error.message}`];\n\t\tconst errorWithCode = error as Error & { code?: string; errno?: number | string; cause?: unknown };\n\t\tif (errorWithCode.code) details.push(`code=${errorWithCode.code}`);\n\t\tif (typeof errorWithCode.errno !== \"undefined\") details.push(`errno=${String(errorWithCode.errno)}`);\n\t\tif (typeof error.cause !== \"undefined\") {\n\t\t\tdetails.push(`cause=${formatErrorDetails(error.cause)}`);\n\t\t}\n\t\tif (error.stack) {\n\t\t\tdetails.push(`stack=${error.stack}`);\n\t\t}\n\t\treturn details.join(\"; \");\n\t}\n\treturn String(error);\n}\n\nasync function startCallbackServer(expectedState: string): Promise<CallbackServerInfo> {\n\tconst { createServer } = await getNodeApis();\n\n\treturn new Promise((resolve, reject) => {\n\t\tlet result: { code: string; state: string } | null = null;\n\t\tlet cancelled = false;\n\n\t\tconst server = createServer((req, res) => {\n\t\t\ttry {\n\t\t\t\tconst url = new URL(req.url || \"\", \"http://localhost\");\n\t\t\t\tif (url.pathname !== CALLBACK_PATH) {\n\t\t\t\t\tres.writeHead(404, { \"Content-Type\": \"text/plain; charset=utf-8\" });\n\t\t\t\t\tres.end(\"Not found\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst code = url.searchParams.get(\"code\");\n\t\t\t\tconst state = url.searchParams.get(\"state\");\n\t\t\t\tconst error = url.searchParams.get(\"error\");\n\n\t\t\t\tif (error) {\n\t\t\t\t\tres.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(`<html><body><h1>Authentication Failed</h1><p>Error: ${error}</p></body></html>`);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!code || !state) {\n\t\t\t\t\tres.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(\n\t\t\t\t\t\t`<html><body><h1>Authentication Failed</h1><p>Missing code or state parameter.</p></body></html>`,\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (state !== expectedState) {\n\t\t\t\t\tres.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(`<html><body><h1>Authentication Failed</h1><p>State mismatch.</p></body></html>`);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tres.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\tres.end(SUCCESS_HTML);\n\t\t\t\tresult = { code, state };\n\t\t\t} catch {\n\t\t\t\tres.writeHead(500, { \"Content-Type\": \"text/plain; charset=utf-8\" });\n\t\t\t\tres.end(\"Internal error\");\n\t\t\t}\n\t\t});\n\n\t\tserver.on(\"error\", (err) => {\n\t\t\treject(err);\n\t\t});\n\n\t\tserver.listen(CALLBACK_PORT, CALLBACK_HOST, () => {\n\t\t\tresolve({\n\t\t\t\tserver,\n\t\t\t\tredirectUri: REDIRECT_URI,\n\t\t\t\tcancelWait: () => {\n\t\t\t\t\tcancelled = true;\n\t\t\t\t},\n\t\t\t\twaitForCode: async () => {\n\t\t\t\t\tconst sleep = () => new Promise((r) => setTimeout(r, 100));\n\t\t\t\t\twhile (!result && !cancelled) {\n\t\t\t\t\t\tawait sleep();\n\t\t\t\t\t}\n\t\t\t\t\treturn result;\n\t\t\t\t},\n\t\t\t});\n\t\t});\n\t});\n}\n\nasync function postJson(url: string, body: Record<string, string | number>): Promise<string> {\n\tconst response = await fetch(url, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t\tAccept: \"application/json\",\n\t\t},\n\t\tbody: JSON.stringify(body),\n\t\tsignal: AbortSignal.timeout(30_000),\n\t});\n\n\tconst responseBody = await response.text();\n\n\tif (!response.ok) {\n\t\tthrow new Error(`HTTP request failed. status=${response.status}; url=${url}; body=${responseBody}`);\n\t}\n\n\treturn responseBody;\n}\n\nasync function exchangeAuthorizationCode(\n\tcode: string,\n\tstate: string,\n\tverifier: string,\n\tredirectUri: string,\n): Promise<OAuthCredentials> {\n\tlet responseBody: string;\n\ttry {\n\t\tresponseBody = await postJson(TOKEN_URL, {\n\t\t\tgrant_type: \"authorization_code\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\tcode,\n\t\t\tstate,\n\t\t\tredirect_uri: redirectUri,\n\t\t\tcode_verifier: verifier,\n\t\t});\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Token exchange request failed. url=${TOKEN_URL}; redirect_uri=${redirectUri}; response_type=authorization_code; details=${formatErrorDetails(error)}`,\n\t\t);\n\t}\n\n\tlet tokenData: { access_token: string; refresh_token: string; expires_in: number };\n\ttry {\n\t\ttokenData = JSON.parse(responseBody) as { access_token: string; refresh_token: string; expires_in: number };\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Token exchange returned invalid JSON. url=${TOKEN_URL}; body=${responseBody}; details=${formatErrorDetails(error)}`,\n\t\t);\n\t}\n\n\treturn {\n\t\trefresh: tokenData.refresh_token,\n\t\taccess: tokenData.access_token,\n\t\texpires: Date.now() + tokenData.expires_in * 1000 - 5 * 60 * 1000,\n\t};\n}\n\n/**\n * Login with Anthropic OAuth (authorization code + PKCE)\n */\nexport async function loginAnthropic(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}): Promise<OAuthCredentials> {\n\tconst { verifier, challenge } = await generatePKCE();\n\tconst server = await startCallbackServer(verifier);\n\n\tlet code: string | undefined;\n\tlet state: string | undefined;\n\tlet redirectUriForExchange = REDIRECT_URI;\n\n\ttry {\n\t\tconst authParams = new URLSearchParams({\n\t\t\tcode: \"true\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\tresponse_type: \"code\",\n\t\t\tredirect_uri: REDIRECT_URI,\n\t\t\tscope: SCOPES,\n\t\t\tcode_challenge: challenge,\n\t\t\tcode_challenge_method: \"S256\",\n\t\t\tstate: verifier,\n\t\t});\n\n\t\toptions.onAuth({\n\t\t\turl: `${AUTHORIZE_URL}?${authParams.toString()}`,\n\t\t\tinstructions:\n\t\t\t\t\"Complete login in your browser. If the browser is on another machine, paste the final redirect URL here.\",\n\t\t});\n\n\t\tif (options.onManualCodeInput) {\n\t\t\tlet manualInput: 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\tmanualInput = 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\n\t\t\tconst result = await server.waitForCode();\n\n\t\t\tif (manualError) {\n\t\t\t\tthrow manualError;\n\t\t\t}\n\n\t\t\tif (result?.code) {\n\t\t\t\tcode = result.code;\n\t\t\t\tstate = result.state;\n\t\t\t\tredirectUriForExchange = REDIRECT_URI;\n\t\t\t} else if (manualInput) {\n\t\t\t\tconst parsed = parseAuthorizationInput(manualInput);\n\t\t\t\tif (parsed.state && parsed.state !== verifier) {\n\t\t\t\t\tthrow new Error(\"OAuth state mismatch\");\n\t\t\t\t}\n\t\t\t\tcode = parsed.code;\n\t\t\t\tstate = parsed.state ?? verifier;\n\t\t\t\tredirectUriForExchange = MANUAL_REDIRECT_URI;\n\t\t\t}\n\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 (manualInput) {\n\t\t\t\t\tconst parsed = parseAuthorizationInput(manualInput);\n\t\t\t\t\tif (parsed.state && parsed.state !== verifier) {\n\t\t\t\t\t\tthrow new Error(\"OAuth state mismatch\");\n\t\t\t\t\t}\n\t\t\t\t\tcode = parsed.code;\n\t\t\t\t\tstate = parsed.state ?? verifier;\n\t\t\t\t\tredirectUriForExchange = MANUAL_REDIRECT_URI;\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\tstate = result.state;\n\t\t\t\tredirectUriForExchange = REDIRECT_URI;\n\t\t\t}\n\t\t}\n\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\tplaceholder: MANUAL_REDIRECT_URI,\n\t\t\t});\n\t\t\tconst parsed = parseAuthorizationInput(input);\n\t\t\tif (parsed.state && parsed.state !== verifier) {\n\t\t\t\tthrow new Error(\"OAuth state mismatch\");\n\t\t\t}\n\t\t\tcode = parsed.code;\n\t\t\tstate = parsed.state ?? verifier;\n\t\t\tredirectUriForExchange = MANUAL_REDIRECT_URI;\n\t\t}\n\n\t\tif (!code) {\n\t\t\tthrow new Error(\"Missing authorization code\");\n\t\t}\n\n\t\tif (!state) {\n\t\t\tthrow new Error(\"Missing OAuth state\");\n\t\t}\n\n\t\toptions.onProgress?.(\"Exchanging authorization code for tokens...\");\n\t\treturn exchangeAuthorizationCode(code, state, verifier, redirectUriForExchange);\n\t} finally {\n\t\tserver.server.close();\n\t}\n}\n\n/**\n * Refresh Anthropic OAuth token\n */\nexport async function refreshAnthropicToken(refreshToken: string): Promise<OAuthCredentials> {\n\tlet responseBody: string;\n\ttry {\n\t\tresponseBody = await postJson(TOKEN_URL, {\n\t\t\tgrant_type: \"refresh_token\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\trefresh_token: refreshToken,\n\t\t\tscope: SCOPES,\n\t\t});\n\t} catch (error) {\n\t\tthrow new Error(`Anthropic token refresh request failed. url=${TOKEN_URL}; details=${formatErrorDetails(error)}`);\n\t}\n\n\tlet data: { access_token: string; refresh_token: string; expires_in: number; scope?: string };\n\ttry {\n\t\tdata = JSON.parse(responseBody) as {\n\t\t\taccess_token: string;\n\t\t\trefresh_token: string;\n\t\t\texpires_in: number;\n\t\t\tscope?: string;\n\t\t};\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Anthropic token refresh returned invalid JSON. url=${TOKEN_URL}; body=${responseBody}; details=${formatErrorDetails(error)}`,\n\t\t);\n\t}\n\n\treturn {\n\t\trefresh: data.refresh_token,\n\t\taccess: data.access_token,\n\t\texpires: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000,\n\t};\n}\n\nexport const anthropicOAuthProvider: OAuthProviderInterface = {\n\tid: \"anthropic\",\n\tname: \"Anthropic (Claude Pro/Max)\",\n\tusesCallbackServer: true,\n\n\tasync login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\t\treturn loginAnthropic({\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\n\tasync refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n\t\treturn refreshAnthropicToken(credentials.refresh);\n\t},\n\n\tgetApiKey(credentials: OAuthCredentials): string {\n\t\treturn credentials.access;\n\t},\n};\n"]}
|
|
1
|
+
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../../src/utils/oauth/anthropic.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAuB,WAAW,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAqO7G;;GAEG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE;IAC7C,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;CAC1C,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA4G5B;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA+B3F;AAED,eAAO,MAAM,sBAAsB,EAAE,sBAqBpC,CAAC","sourcesContent":["/**\n * Anthropic OAuth flow (Claude Pro/Max)\n *\n * NOTE: This module uses Node.js http.createServer for the OAuth callback server.\n * It is only intended for CLI use, not browser environments.\n */\n\nimport type { Server } from \"node:http\";\nimport { generatePKCE } from \"./pkce.js\";\nimport type { OAuthCredentials, OAuthLoginCallbacks, OAuthPrompt, OAuthProviderInterface } from \"./types.js\";\n\ntype CallbackServerInfo = {\n\tserver: Server;\n\tredirectUri: string;\n\tcancelWait: () => void;\n\twaitForCode: () => Promise<{ code: string; state: string } | null>;\n};\n\ntype NodeApis = {\n\tcreateServer: typeof import(\"node:http\").createServer;\n};\n\nlet nodeApis: NodeApis | null = null;\nlet nodeApisPromise: Promise<NodeApis> | null = null;\n\nconst decode = (s: string) => atob(s);\nconst CLIENT_ID = decode(\"OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl\");\nconst AUTHORIZE_URL = \"https://claude.ai/oauth/authorize\";\nconst TOKEN_URL = \"https://platform.claude.com/v1/oauth/token\";\nconst CALLBACK_HOST = \"127.0.0.1\";\nconst CALLBACK_PORT = 53692;\nconst CALLBACK_PATH = \"/callback\";\nconst REDIRECT_URI = `http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`;\nconst SCOPES =\n\t\"org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload\";\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>`;\n\nasync function getNodeApis(): Promise<NodeApis> {\n\tif (nodeApis) return nodeApis;\n\tif (!nodeApisPromise) {\n\t\tif (typeof process === \"undefined\" || (!process.versions?.node && !process.versions?.bun)) {\n\t\t\tthrow new Error(\"Anthropic OAuth is only available in Node.js environments\");\n\t\t}\n\t\tnodeApisPromise = import(\"node:http\").then((httpModule) => ({\n\t\t\tcreateServer: httpModule.createServer,\n\t\t}));\n\t}\n\tnodeApis = await nodeApisPromise;\n\treturn nodeApis;\n}\n\nfunction parseAuthorizationInput(input: string): { code?: string; state?: string } {\n\tconst value = input.trim();\n\tif (!value) return {};\n\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\t\t// not a URL\n\t}\n\n\tif (value.includes(\"#\")) {\n\t\tconst [code, state] = value.split(\"#\", 2);\n\t\treturn { code, state };\n\t}\n\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\n\treturn { code: value };\n}\n\nfunction formatErrorDetails(error: unknown): string {\n\tif (error instanceof Error) {\n\t\tconst details: string[] = [`${error.name}: ${error.message}`];\n\t\tconst errorWithCode = error as Error & { code?: string; errno?: number | string; cause?: unknown };\n\t\tif (errorWithCode.code) details.push(`code=${errorWithCode.code}`);\n\t\tif (typeof errorWithCode.errno !== \"undefined\") details.push(`errno=${String(errorWithCode.errno)}`);\n\t\tif (typeof error.cause !== \"undefined\") {\n\t\t\tdetails.push(`cause=${formatErrorDetails(error.cause)}`);\n\t\t}\n\t\tif (error.stack) {\n\t\t\tdetails.push(`stack=${error.stack}`);\n\t\t}\n\t\treturn details.join(\"; \");\n\t}\n\treturn String(error);\n}\n\nasync function startCallbackServer(expectedState: string): Promise<CallbackServerInfo> {\n\tconst { createServer } = await getNodeApis();\n\n\treturn new Promise((resolve, reject) => {\n\t\tlet result: { code: string; state: string } | null = null;\n\t\tlet cancelled = false;\n\n\t\tconst server = createServer((req, res) => {\n\t\t\ttry {\n\t\t\t\tconst url = new URL(req.url || \"\", \"http://localhost\");\n\t\t\t\tif (url.pathname !== CALLBACK_PATH) {\n\t\t\t\t\tres.writeHead(404, { \"Content-Type\": \"text/plain; charset=utf-8\" });\n\t\t\t\t\tres.end(\"Not found\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst code = url.searchParams.get(\"code\");\n\t\t\t\tconst state = url.searchParams.get(\"state\");\n\t\t\t\tconst error = url.searchParams.get(\"error\");\n\n\t\t\t\tif (error) {\n\t\t\t\t\tres.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(`<html><body><h1>Authentication Failed</h1><p>Error: ${error}</p></body></html>`);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!code || !state) {\n\t\t\t\t\tres.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(\n\t\t\t\t\t\t`<html><body><h1>Authentication Failed</h1><p>Missing code or state parameter.</p></body></html>`,\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (state !== expectedState) {\n\t\t\t\t\tres.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(`<html><body><h1>Authentication Failed</h1><p>State mismatch.</p></body></html>`);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tres.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\tres.end(SUCCESS_HTML);\n\t\t\t\tresult = { code, state };\n\t\t\t} catch {\n\t\t\t\tres.writeHead(500, { \"Content-Type\": \"text/plain; charset=utf-8\" });\n\t\t\t\tres.end(\"Internal error\");\n\t\t\t}\n\t\t});\n\n\t\tserver.on(\"error\", (err) => {\n\t\t\treject(err);\n\t\t});\n\n\t\tserver.listen(CALLBACK_PORT, CALLBACK_HOST, () => {\n\t\t\tresolve({\n\t\t\t\tserver,\n\t\t\t\tredirectUri: REDIRECT_URI,\n\t\t\t\tcancelWait: () => {\n\t\t\t\t\tcancelled = true;\n\t\t\t\t},\n\t\t\t\twaitForCode: async () => {\n\t\t\t\t\tconst sleep = () => new Promise((r) => setTimeout(r, 100));\n\t\t\t\t\twhile (!result && !cancelled) {\n\t\t\t\t\t\tawait sleep();\n\t\t\t\t\t}\n\t\t\t\t\treturn result;\n\t\t\t\t},\n\t\t\t});\n\t\t});\n\t});\n}\n\nasync function postJson(url: string, body: Record<string, string | number>): Promise<string> {\n\tconst response = await fetch(url, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t\tAccept: \"application/json\",\n\t\t},\n\t\tbody: JSON.stringify(body),\n\t\tsignal: AbortSignal.timeout(30_000),\n\t});\n\n\tconst responseBody = await response.text();\n\n\tif (!response.ok) {\n\t\tthrow new Error(`HTTP request failed. status=${response.status}; url=${url}; body=${responseBody}`);\n\t}\n\n\treturn responseBody;\n}\n\nasync function exchangeAuthorizationCode(\n\tcode: string,\n\tstate: string,\n\tverifier: string,\n\tredirectUri: string,\n): Promise<OAuthCredentials> {\n\tlet responseBody: string;\n\ttry {\n\t\tresponseBody = await postJson(TOKEN_URL, {\n\t\t\tgrant_type: \"authorization_code\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\tcode,\n\t\t\tstate,\n\t\t\tredirect_uri: redirectUri,\n\t\t\tcode_verifier: verifier,\n\t\t});\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Token exchange request failed. url=${TOKEN_URL}; redirect_uri=${redirectUri}; response_type=authorization_code; details=${formatErrorDetails(error)}`,\n\t\t);\n\t}\n\n\tlet tokenData: { access_token: string; refresh_token: string; expires_in: number };\n\ttry {\n\t\ttokenData = JSON.parse(responseBody) as { access_token: string; refresh_token: string; expires_in: number };\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Token exchange returned invalid JSON. url=${TOKEN_URL}; body=${responseBody}; details=${formatErrorDetails(error)}`,\n\t\t);\n\t}\n\n\treturn {\n\t\trefresh: tokenData.refresh_token,\n\t\taccess: tokenData.access_token,\n\t\texpires: Date.now() + tokenData.expires_in * 1000 - 5 * 60 * 1000,\n\t};\n}\n\n/**\n * Login with Anthropic OAuth (authorization code + PKCE)\n */\nexport async function loginAnthropic(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}): Promise<OAuthCredentials> {\n\tconst { verifier, challenge } = await generatePKCE();\n\tconst server = await startCallbackServer(verifier);\n\n\tlet code: string | undefined;\n\tlet state: string | undefined;\n\tlet redirectUriForExchange = REDIRECT_URI;\n\n\ttry {\n\t\tconst authParams = new URLSearchParams({\n\t\t\tcode: \"true\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\tresponse_type: \"code\",\n\t\t\tredirect_uri: REDIRECT_URI,\n\t\t\tscope: SCOPES,\n\t\t\tcode_challenge: challenge,\n\t\t\tcode_challenge_method: \"S256\",\n\t\t\tstate: verifier,\n\t\t});\n\n\t\toptions.onAuth({\n\t\t\turl: `${AUTHORIZE_URL}?${authParams.toString()}`,\n\t\t\tinstructions:\n\t\t\t\t\"Complete login in your browser. If the browser is on another machine, paste the final redirect URL here.\",\n\t\t});\n\n\t\tif (options.onManualCodeInput) {\n\t\t\tlet manualInput: 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\tmanualInput = 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\n\t\t\tconst result = await server.waitForCode();\n\n\t\t\tif (manualError) {\n\t\t\t\tthrow manualError;\n\t\t\t}\n\n\t\t\tif (result?.code) {\n\t\t\t\tcode = result.code;\n\t\t\t\tstate = result.state;\n\t\t\t\tredirectUriForExchange = REDIRECT_URI;\n\t\t\t} else if (manualInput) {\n\t\t\t\tconst parsed = parseAuthorizationInput(manualInput);\n\t\t\t\tif (parsed.state && parsed.state !== verifier) {\n\t\t\t\t\tthrow new Error(\"OAuth state mismatch\");\n\t\t\t\t}\n\t\t\t\tcode = parsed.code;\n\t\t\t\tstate = parsed.state ?? verifier;\n\t\t\t}\n\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 (manualInput) {\n\t\t\t\t\tconst parsed = parseAuthorizationInput(manualInput);\n\t\t\t\t\tif (parsed.state && parsed.state !== verifier) {\n\t\t\t\t\t\tthrow new Error(\"OAuth state mismatch\");\n\t\t\t\t\t}\n\t\t\t\t\tcode = parsed.code;\n\t\t\t\t\tstate = parsed.state ?? verifier;\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\tstate = result.state;\n\t\t\t\tredirectUriForExchange = REDIRECT_URI;\n\t\t\t}\n\t\t}\n\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\tplaceholder: REDIRECT_URI,\n\t\t\t});\n\t\t\tconst parsed = parseAuthorizationInput(input);\n\t\t\tif (parsed.state && parsed.state !== verifier) {\n\t\t\t\tthrow new Error(\"OAuth state mismatch\");\n\t\t\t}\n\t\t\tcode = parsed.code;\n\t\t\tstate = parsed.state ?? verifier;\n\t\t}\n\n\t\tif (!code) {\n\t\t\tthrow new Error(\"Missing authorization code\");\n\t\t}\n\n\t\tif (!state) {\n\t\t\tthrow new Error(\"Missing OAuth state\");\n\t\t}\n\n\t\toptions.onProgress?.(\"Exchanging authorization code for tokens...\");\n\t\treturn exchangeAuthorizationCode(code, state, verifier, redirectUriForExchange);\n\t} finally {\n\t\tserver.server.close();\n\t}\n}\n\n/**\n * Refresh Anthropic OAuth token\n */\nexport async function refreshAnthropicToken(refreshToken: string): Promise<OAuthCredentials> {\n\tlet responseBody: string;\n\ttry {\n\t\tresponseBody = await postJson(TOKEN_URL, {\n\t\t\tgrant_type: \"refresh_token\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\trefresh_token: refreshToken,\n\t\t});\n\t} catch (error) {\n\t\tthrow new Error(`Anthropic token refresh request failed. url=${TOKEN_URL}; details=${formatErrorDetails(error)}`);\n\t}\n\n\tlet data: { access_token: string; refresh_token: string; expires_in: number; scope?: string };\n\ttry {\n\t\tdata = JSON.parse(responseBody) as {\n\t\t\taccess_token: string;\n\t\t\trefresh_token: string;\n\t\t\texpires_in: number;\n\t\t\tscope?: string;\n\t\t};\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Anthropic token refresh returned invalid JSON. url=${TOKEN_URL}; body=${responseBody}; details=${formatErrorDetails(error)}`,\n\t\t);\n\t}\n\n\treturn {\n\t\trefresh: data.refresh_token,\n\t\taccess: data.access_token,\n\t\texpires: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000,\n\t};\n}\n\nexport const anthropicOAuthProvider: OAuthProviderInterface = {\n\tid: \"anthropic\",\n\tname: \"Anthropic (Claude Pro/Max)\",\n\tusesCallbackServer: true,\n\n\tasync login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\t\treturn loginAnthropic({\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\n\tasync refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n\t\treturn refreshAnthropicToken(credentials.refresh);\n\t},\n\n\tgetApiKey(credentials: OAuthCredentials): string {\n\t\treturn credentials.access;\n\t},\n};\n"]}
|
|
@@ -11,7 +11,6 @@ const decode = (s) => atob(s);
|
|
|
11
11
|
const CLIENT_ID = decode("OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl");
|
|
12
12
|
const AUTHORIZE_URL = "https://claude.ai/oauth/authorize";
|
|
13
13
|
const TOKEN_URL = "https://platform.claude.com/v1/oauth/token";
|
|
14
|
-
const MANUAL_REDIRECT_URI = "https://platform.claude.com/oauth/code/callback";
|
|
15
14
|
const CALLBACK_HOST = "127.0.0.1";
|
|
16
15
|
const CALLBACK_PORT = 53692;
|
|
17
16
|
const CALLBACK_PATH = "/callback";
|
|
@@ -245,7 +244,6 @@ export async function loginAnthropic(options) {
|
|
|
245
244
|
}
|
|
246
245
|
code = parsed.code;
|
|
247
246
|
state = parsed.state ?? verifier;
|
|
248
|
-
redirectUriForExchange = MANUAL_REDIRECT_URI;
|
|
249
247
|
}
|
|
250
248
|
if (!code) {
|
|
251
249
|
await manualPromise;
|
|
@@ -259,7 +257,6 @@ export async function loginAnthropic(options) {
|
|
|
259
257
|
}
|
|
260
258
|
code = parsed.code;
|
|
261
259
|
state = parsed.state ?? verifier;
|
|
262
|
-
redirectUriForExchange = MANUAL_REDIRECT_URI;
|
|
263
260
|
}
|
|
264
261
|
}
|
|
265
262
|
}
|
|
@@ -274,7 +271,7 @@ export async function loginAnthropic(options) {
|
|
|
274
271
|
if (!code) {
|
|
275
272
|
const input = await options.onPrompt({
|
|
276
273
|
message: "Paste the authorization code or full redirect URL:",
|
|
277
|
-
placeholder:
|
|
274
|
+
placeholder: REDIRECT_URI,
|
|
278
275
|
});
|
|
279
276
|
const parsed = parseAuthorizationInput(input);
|
|
280
277
|
if (parsed.state && parsed.state !== verifier) {
|
|
@@ -282,7 +279,6 @@ export async function loginAnthropic(options) {
|
|
|
282
279
|
}
|
|
283
280
|
code = parsed.code;
|
|
284
281
|
state = parsed.state ?? verifier;
|
|
285
|
-
redirectUriForExchange = MANUAL_REDIRECT_URI;
|
|
286
282
|
}
|
|
287
283
|
if (!code) {
|
|
288
284
|
throw new Error("Missing authorization code");
|
|
@@ -307,7 +303,6 @@ export async function refreshAnthropicToken(refreshToken) {
|
|
|
307
303
|
grant_type: "refresh_token",
|
|
308
304
|
client_id: CLIENT_ID,
|
|
309
305
|
refresh_token: refreshToken,
|
|
310
|
-
scope: SCOPES,
|
|
311
306
|
});
|
|
312
307
|
}
|
|
313
308
|
catch (error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../src/utils/oauth/anthropic.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAczC,IAAI,QAAQ,GAAoB,IAAI,CAAC;AACrC,IAAI,eAAe,GAA6B,IAAI,CAAC;AAErD,MAAM,MAAM,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACtC,MAAM,SAAS,GAAG,MAAM,CAAC,kDAAkD,CAAC,CAAC;AAC7E,MAAM,aAAa,GAAG,mCAAmC,CAAC;AAC1D,MAAM,SAAS,GAAG,4CAA4C,CAAC;AAC/D,MAAM,mBAAmB,GAAG,iDAAiD,CAAC;AAC9E,MAAM,aAAa,GAAG,WAAW,CAAC;AAClC,MAAM,aAAa,GAAG,KAAK,CAAC;AAC5B,MAAM,aAAa,GAAG,WAAW,CAAC;AAClC,MAAM,YAAY,GAAG,oBAAoB,aAAa,GAAG,aAAa,EAAE,CAAC;AACzE,MAAM,MAAM,GACX,4GAA4G,CAAC;AAC9G,MAAM,YAAY,GAAG;;;;;;;;;;QAUb,CAAC;AAET,KAAK,UAAU,WAAW,GAAsB;IAC/C,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC9B,IAAI,CAAC,eAAe,EAAE,CAAC;QACtB,IAAI,OAAO,OAAO,KAAK,WAAW,IAAI,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,CAAC;YAC3F,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;QAC9E,CAAC;QACD,eAAe,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;YAC3D,YAAY,EAAE,UAAU,CAAC,YAAY;SACrC,CAAC,CAAC,CAAC;IACL,CAAC;IACD,QAAQ,GAAG,MAAM,eAAe,CAAC;IACjC,OAAO,QAAQ,CAAC;AAAA,CAChB;AAED,SAAS,uBAAuB,CAAC,KAAa,EAAqC;IAClF,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IAEtB,IAAI,CAAC;QACJ,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;QAC3B,OAAO;YACN,IAAI,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,SAAS;YAC/C,KAAK,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,SAAS;SACjD,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACR,YAAY;IACb,CAAC;IAED,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAC1C,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IACxB,CAAC;IAED,IAAI,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,KAAK,CAAC,CAAC;QAC1C,OAAO;YACN,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,SAAS;YACrC,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,SAAS;SACvC,CAAC;IACH,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AAAA,CACvB;AAED,SAAS,kBAAkB,CAAC,KAAc,EAAU;IACnD,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAa,CAAC,GAAG,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAC9D,MAAM,aAAa,GAAG,KAA4E,CAAC;QACnG,IAAI,aAAa,CAAC,IAAI;YAAE,OAAO,CAAC,IAAI,CAAC,QAAQ,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC;QACnE,IAAI,OAAO,aAAa,CAAC,KAAK,KAAK,WAAW;YAAE,OAAO,CAAC,IAAI,CAAC,SAAS,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACrG,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,WAAW,EAAE,CAAC;YACxC,OAAO,CAAC,IAAI,CAAC,SAAS,kBAAkB,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC1D,CAAC;QACD,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YACjB,OAAO,CAAC,IAAI,CAAC,SAAS,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;QACtC,CAAC;QACD,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;IACD,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;AAAA,CACrB;AAED,KAAK,UAAU,mBAAmB,CAAC,aAAqB,EAA+B;IACtF,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,WAAW,EAAE,CAAC;IAE7C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC;QACvC,IAAI,MAAM,GAA2C,IAAI,CAAC;QAC1D,IAAI,SAAS,GAAG,KAAK,CAAC;QAEtB,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC;YACzC,IAAI,CAAC;gBACJ,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,EAAE,kBAAkB,CAAC,CAAC;gBACvD,IAAI,GAAG,CAAC,QAAQ,KAAK,aAAa,EAAE,CAAC;oBACpC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,2BAA2B,EAAE,CAAC,CAAC;oBACpE,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;oBACrB,OAAO;gBACR,CAAC;gBAED,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBAC1C,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBAC5C,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBAE5C,IAAI,KAAK,EAAE,CAAC;oBACX,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,0BAA0B,EAAE,CAAC,CAAC;oBACnE,GAAG,CAAC,GAAG,CAAC,uDAAuD,KAAK,oBAAoB,CAAC,CAAC;oBAC1F,OAAO;gBACR,CAAC;gBAED,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;oBACrB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,0BAA0B,EAAE,CAAC,CAAC;oBACnE,GAAG,CAAC,GAAG,CACN,iGAAiG,CACjG,CAAC;oBACF,OAAO;gBACR,CAAC;gBAED,IAAI,KAAK,KAAK,aAAa,EAAE,CAAC;oBAC7B,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,0BAA0B,EAAE,CAAC,CAAC;oBACnE,GAAG,CAAC,GAAG,CAAC,gFAAgF,CAAC,CAAC;oBAC1F,OAAO;gBACR,CAAC;gBAED,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,0BAA0B,EAAE,CAAC,CAAC;gBACnE,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;gBACtB,MAAM,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;YAC1B,CAAC;YAAC,MAAM,CAAC;gBACR,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,2BAA2B,EAAE,CAAC,CAAC;gBACpE,GAAG,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;YAC3B,CAAC;QAAA,CACD,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC;YAC3B,MAAM,CAAC,GAAG,CAAC,CAAC;QAAA,CACZ,CAAC,CAAC;QAEH,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,aAAa,EAAE,GAAG,EAAE,CAAC;YACjD,OAAO,CAAC;gBACP,MAAM;gBACN,WAAW,EAAE,YAAY;gBACzB,UAAU,EAAE,GAAG,EAAE,CAAC;oBACjB,SAAS,GAAG,IAAI,CAAC;gBAAA,CACjB;gBACD,WAAW,EAAE,KAAK,IAAI,EAAE,CAAC;oBACxB,MAAM,KAAK,GAAG,GAAG,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;oBAC3D,OAAO,CAAC,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;wBAC9B,MAAM,KAAK,EAAE,CAAC;oBACf,CAAC;oBACD,OAAO,MAAM,CAAC;gBAAA,CACd;aACD,CAAC,CAAC;QAAA,CACH,CAAC,CAAC;IAAA,CACH,CAAC,CAAC;AAAA,CACH;AAED,KAAK,UAAU,QAAQ,CAAC,GAAW,EAAE,IAAqC,EAAmB;IAC5F,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QACjC,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACR,cAAc,EAAE,kBAAkB;YAClC,MAAM,EAAE,kBAAkB;SAC1B;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;QAC1B,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC;KACnC,CAAC,CAAC;IAEH,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAE3C,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,+BAA+B,QAAQ,CAAC,MAAM,SAAS,GAAG,UAAU,YAAY,EAAE,CAAC,CAAC;IACrG,CAAC;IAED,OAAO,YAAY,CAAC;AAAA,CACpB;AAED,KAAK,UAAU,yBAAyB,CACvC,IAAY,EACZ,KAAa,EACb,QAAgB,EAChB,WAAmB,EACS;IAC5B,IAAI,YAAoB,CAAC;IACzB,IAAI,CAAC;QACJ,YAAY,GAAG,MAAM,QAAQ,CAAC,SAAS,EAAE;YACxC,UAAU,EAAE,oBAAoB;YAChC,SAAS,EAAE,SAAS;YACpB,IAAI;YACJ,KAAK;YACL,YAAY,EAAE,WAAW;YACzB,aAAa,EAAE,QAAQ;SACvB,CAAC,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CACd,sCAAsC,SAAS,kBAAkB,WAAW,+CAA+C,kBAAkB,CAAC,KAAK,CAAC,EAAE,CACtJ,CAAC;IACH,CAAC;IAED,IAAI,SAA8E,CAAC;IACnF,IAAI,CAAC;QACJ,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAwE,CAAC;IAC7G,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CACd,6CAA6C,SAAS,UAAU,YAAY,aAAa,kBAAkB,CAAC,KAAK,CAAC,EAAE,CACpH,CAAC;IACH,CAAC;IAED,OAAO;QACN,OAAO,EAAE,SAAS,CAAC,aAAa;QAChC,MAAM,EAAE,SAAS,CAAC,YAAY;QAC9B,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,UAAU,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI;KACjE,CAAC;AAAA,CACF;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAKpC,EAA6B;IAC7B,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,MAAM,YAAY,EAAE,CAAC;IACrD,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAEnD,IAAI,IAAwB,CAAC;IAC7B,IAAI,KAAyB,CAAC;IAC9B,IAAI,sBAAsB,GAAG,YAAY,CAAC;IAE1C,IAAI,CAAC;QACJ,MAAM,UAAU,GAAG,IAAI,eAAe,CAAC;YACtC,IAAI,EAAE,MAAM;YACZ,SAAS,EAAE,SAAS;YACpB,aAAa,EAAE,MAAM;YACrB,YAAY,EAAE,YAAY;YAC1B,KAAK,EAAE,MAAM;YACb,cAAc,EAAE,SAAS;YACzB,qBAAqB,EAAE,MAAM;YAC7B,KAAK,EAAE,QAAQ;SACf,CAAC,CAAC;QAEH,OAAO,CAAC,MAAM,CAAC;YACd,GAAG,EAAE,GAAG,aAAa,IAAI,UAAU,CAAC,QAAQ,EAAE,EAAE;YAChD,YAAY,EACX,0GAA0G;SAC3G,CAAC,CAAC;QAEH,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC;YAC/B,IAAI,WAA+B,CAAC;YACpC,IAAI,WAA8B,CAAC;YACnC,MAAM,aAAa,GAAG,OAAO;iBAC3B,iBAAiB,EAAE;iBACnB,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;gBAChB,WAAW,GAAG,KAAK,CAAC;gBACpB,MAAM,CAAC,UAAU,EAAE,CAAC;YAAA,CACpB,CAAC;iBACD,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC;gBACf,WAAW,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;gBAClE,MAAM,CAAC,UAAU,EAAE,CAAC;YAAA,CACpB,CAAC,CAAC;YAEJ,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;YAE1C,IAAI,WAAW,EAAE,CAAC;gBACjB,MAAM,WAAW,CAAC;YACnB,CAAC;YAED,IAAI,MAAM,EAAE,IAAI,EAAE,CAAC;gBAClB,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;gBACnB,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;gBACrB,sBAAsB,GAAG,YAAY,CAAC;YACvC,CAAC;iBAAM,IAAI,WAAW,EAAE,CAAC;gBACxB,MAAM,MAAM,GAAG,uBAAuB,CAAC,WAAW,CAAC,CAAC;gBACpD,IAAI,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;oBAC/C,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;gBACzC,CAAC;gBACD,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;gBACnB,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,QAAQ,CAAC;gBACjC,sBAAsB,GAAG,mBAAmB,CAAC;YAC9C,CAAC;YAED,IAAI,CAAC,IAAI,EAAE,CAAC;gBACX,MAAM,aAAa,CAAC;gBACpB,IAAI,WAAW,EAAE,CAAC;oBACjB,MAAM,WAAW,CAAC;gBACnB,CAAC;gBACD,IAAI,WAAW,EAAE,CAAC;oBACjB,MAAM,MAAM,GAAG,uBAAuB,CAAC,WAAW,CAAC,CAAC;oBACpD,IAAI,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;wBAC/C,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;oBACzC,CAAC;oBACD,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;oBACnB,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,QAAQ,CAAC;oBACjC,sBAAsB,GAAG,mBAAmB,CAAC;gBAC9C,CAAC;YACF,CAAC;QACF,CAAC;aAAM,CAAC;YACP,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;YAC1C,IAAI,MAAM,EAAE,IAAI,EAAE,CAAC;gBAClB,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;gBACnB,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;gBACrB,sBAAsB,GAAG,YAAY,CAAC;YACvC,CAAC;QACF,CAAC;QAED,IAAI,CAAC,IAAI,EAAE,CAAC;YACX,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC;gBACpC,OAAO,EAAE,oDAAoD;gBAC7D,WAAW,EAAE,mBAAmB;aAChC,CAAC,CAAC;YACH,MAAM,MAAM,GAAG,uBAAuB,CAAC,KAAK,CAAC,CAAC;YAC9C,IAAI,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAC/C,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;YACzC,CAAC;YACD,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;YACnB,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,QAAQ,CAAC;YACjC,sBAAsB,GAAG,mBAAmB,CAAC;QAC9C,CAAC;QAED,IAAI,CAAC,IAAI,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAC/C,CAAC;QAED,IAAI,CAAC,KAAK,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;QACxC,CAAC;QAED,OAAO,CAAC,UAAU,EAAE,CAAC,6CAA6C,CAAC,CAAC;QACpE,OAAO,yBAAyB,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,sBAAsB,CAAC,CAAC;IACjF,CAAC;YAAS,CAAC;QACV,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;AAAA,CACD;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,YAAoB,EAA6B;IAC5F,IAAI,YAAoB,CAAC;IACzB,IAAI,CAAC;QACJ,YAAY,GAAG,MAAM,QAAQ,CAAC,SAAS,EAAE;YACxC,UAAU,EAAE,eAAe;YAC3B,SAAS,EAAE,SAAS;YACpB,aAAa,EAAE,YAAY;YAC3B,KAAK,EAAE,MAAM;SACb,CAAC,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,+CAA+C,SAAS,aAAa,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACnH,CAAC;IAED,IAAI,IAAyF,CAAC;IAC9F,IAAI,CAAC;QACJ,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAK7B,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CACd,sDAAsD,SAAS,UAAU,YAAY,aAAa,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAC7H,CAAC;IACH,CAAC;IAED,OAAO;QACN,OAAO,EAAE,IAAI,CAAC,aAAa;QAC3B,MAAM,EAAE,IAAI,CAAC,YAAY;QACzB,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI;KAC5D,CAAC;AAAA,CACF;AAED,MAAM,CAAC,MAAM,sBAAsB,GAA2B;IAC7D,EAAE,EAAE,WAAW;IACf,IAAI,EAAE,4BAA4B;IAClC,kBAAkB,EAAE,IAAI;IAExB,KAAK,CAAC,KAAK,CAAC,SAA8B,EAA6B;QACtE,OAAO,cAAc,CAAC;YACrB,MAAM,EAAE,SAAS,CAAC,MAAM;YACxB,QAAQ,EAAE,SAAS,CAAC,QAAQ;YAC5B,UAAU,EAAE,SAAS,CAAC,UAAU;YAChC,iBAAiB,EAAE,SAAS,CAAC,iBAAiB;SAC9C,CAAC,CAAC;IAAA,CACH;IAED,KAAK,CAAC,YAAY,CAAC,WAA6B,EAA6B;QAC5E,OAAO,qBAAqB,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IAAA,CAClD;IAED,SAAS,CAAC,WAA6B,EAAU;QAChD,OAAO,WAAW,CAAC,MAAM,CAAC;IAAA,CAC1B;CACD,CAAC","sourcesContent":["/**\n * Anthropic OAuth flow (Claude Pro/Max)\n *\n * NOTE: This module uses Node.js http.createServer for the OAuth callback server.\n * It is only intended for CLI use, not browser environments.\n */\n\nimport type { Server } from \"node:http\";\nimport { generatePKCE } from \"./pkce.js\";\nimport type { OAuthCredentials, OAuthLoginCallbacks, OAuthPrompt, OAuthProviderInterface } from \"./types.js\";\n\ntype CallbackServerInfo = {\n\tserver: Server;\n\tredirectUri: string;\n\tcancelWait: () => void;\n\twaitForCode: () => Promise<{ code: string; state: string } | null>;\n};\n\ntype NodeApis = {\n\tcreateServer: typeof import(\"node:http\").createServer;\n};\n\nlet nodeApis: NodeApis | null = null;\nlet nodeApisPromise: Promise<NodeApis> | null = null;\n\nconst decode = (s: string) => atob(s);\nconst CLIENT_ID = decode(\"OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl\");\nconst AUTHORIZE_URL = \"https://claude.ai/oauth/authorize\";\nconst TOKEN_URL = \"https://platform.claude.com/v1/oauth/token\";\nconst MANUAL_REDIRECT_URI = \"https://platform.claude.com/oauth/code/callback\";\nconst CALLBACK_HOST = \"127.0.0.1\";\nconst CALLBACK_PORT = 53692;\nconst CALLBACK_PATH = \"/callback\";\nconst REDIRECT_URI = `http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`;\nconst SCOPES =\n\t\"org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload\";\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>`;\n\nasync function getNodeApis(): Promise<NodeApis> {\n\tif (nodeApis) return nodeApis;\n\tif (!nodeApisPromise) {\n\t\tif (typeof process === \"undefined\" || (!process.versions?.node && !process.versions?.bun)) {\n\t\t\tthrow new Error(\"Anthropic OAuth is only available in Node.js environments\");\n\t\t}\n\t\tnodeApisPromise = import(\"node:http\").then((httpModule) => ({\n\t\t\tcreateServer: httpModule.createServer,\n\t\t}));\n\t}\n\tnodeApis = await nodeApisPromise;\n\treturn nodeApis;\n}\n\nfunction parseAuthorizationInput(input: string): { code?: string; state?: string } {\n\tconst value = input.trim();\n\tif (!value) return {};\n\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\t\t// not a URL\n\t}\n\n\tif (value.includes(\"#\")) {\n\t\tconst [code, state] = value.split(\"#\", 2);\n\t\treturn { code, state };\n\t}\n\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\n\treturn { code: value };\n}\n\nfunction formatErrorDetails(error: unknown): string {\n\tif (error instanceof Error) {\n\t\tconst details: string[] = [`${error.name}: ${error.message}`];\n\t\tconst errorWithCode = error as Error & { code?: string; errno?: number | string; cause?: unknown };\n\t\tif (errorWithCode.code) details.push(`code=${errorWithCode.code}`);\n\t\tif (typeof errorWithCode.errno !== \"undefined\") details.push(`errno=${String(errorWithCode.errno)}`);\n\t\tif (typeof error.cause !== \"undefined\") {\n\t\t\tdetails.push(`cause=${formatErrorDetails(error.cause)}`);\n\t\t}\n\t\tif (error.stack) {\n\t\t\tdetails.push(`stack=${error.stack}`);\n\t\t}\n\t\treturn details.join(\"; \");\n\t}\n\treturn String(error);\n}\n\nasync function startCallbackServer(expectedState: string): Promise<CallbackServerInfo> {\n\tconst { createServer } = await getNodeApis();\n\n\treturn new Promise((resolve, reject) => {\n\t\tlet result: { code: string; state: string } | null = null;\n\t\tlet cancelled = false;\n\n\t\tconst server = createServer((req, res) => {\n\t\t\ttry {\n\t\t\t\tconst url = new URL(req.url || \"\", \"http://localhost\");\n\t\t\t\tif (url.pathname !== CALLBACK_PATH) {\n\t\t\t\t\tres.writeHead(404, { \"Content-Type\": \"text/plain; charset=utf-8\" });\n\t\t\t\t\tres.end(\"Not found\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst code = url.searchParams.get(\"code\");\n\t\t\t\tconst state = url.searchParams.get(\"state\");\n\t\t\t\tconst error = url.searchParams.get(\"error\");\n\n\t\t\t\tif (error) {\n\t\t\t\t\tres.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(`<html><body><h1>Authentication Failed</h1><p>Error: ${error}</p></body></html>`);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!code || !state) {\n\t\t\t\t\tres.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(\n\t\t\t\t\t\t`<html><body><h1>Authentication Failed</h1><p>Missing code or state parameter.</p></body></html>`,\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (state !== expectedState) {\n\t\t\t\t\tres.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(`<html><body><h1>Authentication Failed</h1><p>State mismatch.</p></body></html>`);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tres.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\tres.end(SUCCESS_HTML);\n\t\t\t\tresult = { code, state };\n\t\t\t} catch {\n\t\t\t\tres.writeHead(500, { \"Content-Type\": \"text/plain; charset=utf-8\" });\n\t\t\t\tres.end(\"Internal error\");\n\t\t\t}\n\t\t});\n\n\t\tserver.on(\"error\", (err) => {\n\t\t\treject(err);\n\t\t});\n\n\t\tserver.listen(CALLBACK_PORT, CALLBACK_HOST, () => {\n\t\t\tresolve({\n\t\t\t\tserver,\n\t\t\t\tredirectUri: REDIRECT_URI,\n\t\t\t\tcancelWait: () => {\n\t\t\t\t\tcancelled = true;\n\t\t\t\t},\n\t\t\t\twaitForCode: async () => {\n\t\t\t\t\tconst sleep = () => new Promise((r) => setTimeout(r, 100));\n\t\t\t\t\twhile (!result && !cancelled) {\n\t\t\t\t\t\tawait sleep();\n\t\t\t\t\t}\n\t\t\t\t\treturn result;\n\t\t\t\t},\n\t\t\t});\n\t\t});\n\t});\n}\n\nasync function postJson(url: string, body: Record<string, string | number>): Promise<string> {\n\tconst response = await fetch(url, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t\tAccept: \"application/json\",\n\t\t},\n\t\tbody: JSON.stringify(body),\n\t\tsignal: AbortSignal.timeout(30_000),\n\t});\n\n\tconst responseBody = await response.text();\n\n\tif (!response.ok) {\n\t\tthrow new Error(`HTTP request failed. status=${response.status}; url=${url}; body=${responseBody}`);\n\t}\n\n\treturn responseBody;\n}\n\nasync function exchangeAuthorizationCode(\n\tcode: string,\n\tstate: string,\n\tverifier: string,\n\tredirectUri: string,\n): Promise<OAuthCredentials> {\n\tlet responseBody: string;\n\ttry {\n\t\tresponseBody = await postJson(TOKEN_URL, {\n\t\t\tgrant_type: \"authorization_code\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\tcode,\n\t\t\tstate,\n\t\t\tredirect_uri: redirectUri,\n\t\t\tcode_verifier: verifier,\n\t\t});\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Token exchange request failed. url=${TOKEN_URL}; redirect_uri=${redirectUri}; response_type=authorization_code; details=${formatErrorDetails(error)}`,\n\t\t);\n\t}\n\n\tlet tokenData: { access_token: string; refresh_token: string; expires_in: number };\n\ttry {\n\t\ttokenData = JSON.parse(responseBody) as { access_token: string; refresh_token: string; expires_in: number };\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Token exchange returned invalid JSON. url=${TOKEN_URL}; body=${responseBody}; details=${formatErrorDetails(error)}`,\n\t\t);\n\t}\n\n\treturn {\n\t\trefresh: tokenData.refresh_token,\n\t\taccess: tokenData.access_token,\n\t\texpires: Date.now() + tokenData.expires_in * 1000 - 5 * 60 * 1000,\n\t};\n}\n\n/**\n * Login with Anthropic OAuth (authorization code + PKCE)\n */\nexport async function loginAnthropic(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}): Promise<OAuthCredentials> {\n\tconst { verifier, challenge } = await generatePKCE();\n\tconst server = await startCallbackServer(verifier);\n\n\tlet code: string | undefined;\n\tlet state: string | undefined;\n\tlet redirectUriForExchange = REDIRECT_URI;\n\n\ttry {\n\t\tconst authParams = new URLSearchParams({\n\t\t\tcode: \"true\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\tresponse_type: \"code\",\n\t\t\tredirect_uri: REDIRECT_URI,\n\t\t\tscope: SCOPES,\n\t\t\tcode_challenge: challenge,\n\t\t\tcode_challenge_method: \"S256\",\n\t\t\tstate: verifier,\n\t\t});\n\n\t\toptions.onAuth({\n\t\t\turl: `${AUTHORIZE_URL}?${authParams.toString()}`,\n\t\t\tinstructions:\n\t\t\t\t\"Complete login in your browser. If the browser is on another machine, paste the final redirect URL here.\",\n\t\t});\n\n\t\tif (options.onManualCodeInput) {\n\t\t\tlet manualInput: 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\tmanualInput = 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\n\t\t\tconst result = await server.waitForCode();\n\n\t\t\tif (manualError) {\n\t\t\t\tthrow manualError;\n\t\t\t}\n\n\t\t\tif (result?.code) {\n\t\t\t\tcode = result.code;\n\t\t\t\tstate = result.state;\n\t\t\t\tredirectUriForExchange = REDIRECT_URI;\n\t\t\t} else if (manualInput) {\n\t\t\t\tconst parsed = parseAuthorizationInput(manualInput);\n\t\t\t\tif (parsed.state && parsed.state !== verifier) {\n\t\t\t\t\tthrow new Error(\"OAuth state mismatch\");\n\t\t\t\t}\n\t\t\t\tcode = parsed.code;\n\t\t\t\tstate = parsed.state ?? verifier;\n\t\t\t\tredirectUriForExchange = MANUAL_REDIRECT_URI;\n\t\t\t}\n\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 (manualInput) {\n\t\t\t\t\tconst parsed = parseAuthorizationInput(manualInput);\n\t\t\t\t\tif (parsed.state && parsed.state !== verifier) {\n\t\t\t\t\t\tthrow new Error(\"OAuth state mismatch\");\n\t\t\t\t\t}\n\t\t\t\t\tcode = parsed.code;\n\t\t\t\t\tstate = parsed.state ?? verifier;\n\t\t\t\t\tredirectUriForExchange = MANUAL_REDIRECT_URI;\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\tstate = result.state;\n\t\t\t\tredirectUriForExchange = REDIRECT_URI;\n\t\t\t}\n\t\t}\n\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\tplaceholder: MANUAL_REDIRECT_URI,\n\t\t\t});\n\t\t\tconst parsed = parseAuthorizationInput(input);\n\t\t\tif (parsed.state && parsed.state !== verifier) {\n\t\t\t\tthrow new Error(\"OAuth state mismatch\");\n\t\t\t}\n\t\t\tcode = parsed.code;\n\t\t\tstate = parsed.state ?? verifier;\n\t\t\tredirectUriForExchange = MANUAL_REDIRECT_URI;\n\t\t}\n\n\t\tif (!code) {\n\t\t\tthrow new Error(\"Missing authorization code\");\n\t\t}\n\n\t\tif (!state) {\n\t\t\tthrow new Error(\"Missing OAuth state\");\n\t\t}\n\n\t\toptions.onProgress?.(\"Exchanging authorization code for tokens...\");\n\t\treturn exchangeAuthorizationCode(code, state, verifier, redirectUriForExchange);\n\t} finally {\n\t\tserver.server.close();\n\t}\n}\n\n/**\n * Refresh Anthropic OAuth token\n */\nexport async function refreshAnthropicToken(refreshToken: string): Promise<OAuthCredentials> {\n\tlet responseBody: string;\n\ttry {\n\t\tresponseBody = await postJson(TOKEN_URL, {\n\t\t\tgrant_type: \"refresh_token\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\trefresh_token: refreshToken,\n\t\t\tscope: SCOPES,\n\t\t});\n\t} catch (error) {\n\t\tthrow new Error(`Anthropic token refresh request failed. url=${TOKEN_URL}; details=${formatErrorDetails(error)}`);\n\t}\n\n\tlet data: { access_token: string; refresh_token: string; expires_in: number; scope?: string };\n\ttry {\n\t\tdata = JSON.parse(responseBody) as {\n\t\t\taccess_token: string;\n\t\t\trefresh_token: string;\n\t\t\texpires_in: number;\n\t\t\tscope?: string;\n\t\t};\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Anthropic token refresh returned invalid JSON. url=${TOKEN_URL}; body=${responseBody}; details=${formatErrorDetails(error)}`,\n\t\t);\n\t}\n\n\treturn {\n\t\trefresh: data.refresh_token,\n\t\taccess: data.access_token,\n\t\texpires: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000,\n\t};\n}\n\nexport const anthropicOAuthProvider: OAuthProviderInterface = {\n\tid: \"anthropic\",\n\tname: \"Anthropic (Claude Pro/Max)\",\n\tusesCallbackServer: true,\n\n\tasync login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\t\treturn loginAnthropic({\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\n\tasync refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n\t\treturn refreshAnthropicToken(credentials.refresh);\n\t},\n\n\tgetApiKey(credentials: OAuthCredentials): string {\n\t\treturn credentials.access;\n\t},\n};\n"]}
|
|
1
|
+
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../src/utils/oauth/anthropic.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Anthropic OAuth flow (Claude Pro/Max)\n *\n * NOTE: This module uses Node.js http.createServer for the OAuth callback server.\n * It is only intended for CLI use, not browser environments.\n */\n\nimport type { Server } from \"node:http\";\nimport { generatePKCE } from \"./pkce.js\";\nimport type { OAuthCredentials, OAuthLoginCallbacks, OAuthPrompt, OAuthProviderInterface } from \"./types.js\";\n\ntype CallbackServerInfo = {\n\tserver: Server;\n\tredirectUri: string;\n\tcancelWait: () => void;\n\twaitForCode: () => Promise<{ code: string; state: string } | null>;\n};\n\ntype NodeApis = {\n\tcreateServer: typeof import(\"node:http\").createServer;\n};\n\nlet nodeApis: NodeApis | null = null;\nlet nodeApisPromise: Promise<NodeApis> | null = null;\n\nconst decode = (s: string) => atob(s);\nconst CLIENT_ID = decode(\"OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl\");\nconst AUTHORIZE_URL = \"https://claude.ai/oauth/authorize\";\nconst TOKEN_URL = \"https://platform.claude.com/v1/oauth/token\";\nconst CALLBACK_HOST = \"127.0.0.1\";\nconst CALLBACK_PORT = 53692;\nconst CALLBACK_PATH = \"/callback\";\nconst REDIRECT_URI = `http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`;\nconst SCOPES =\n\t\"org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload\";\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>`;\n\nasync function getNodeApis(): Promise<NodeApis> {\n\tif (nodeApis) return nodeApis;\n\tif (!nodeApisPromise) {\n\t\tif (typeof process === \"undefined\" || (!process.versions?.node && !process.versions?.bun)) {\n\t\t\tthrow new Error(\"Anthropic OAuth is only available in Node.js environments\");\n\t\t}\n\t\tnodeApisPromise = import(\"node:http\").then((httpModule) => ({\n\t\t\tcreateServer: httpModule.createServer,\n\t\t}));\n\t}\n\tnodeApis = await nodeApisPromise;\n\treturn nodeApis;\n}\n\nfunction parseAuthorizationInput(input: string): { code?: string; state?: string } {\n\tconst value = input.trim();\n\tif (!value) return {};\n\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\t\t// not a URL\n\t}\n\n\tif (value.includes(\"#\")) {\n\t\tconst [code, state] = value.split(\"#\", 2);\n\t\treturn { code, state };\n\t}\n\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\n\treturn { code: value };\n}\n\nfunction formatErrorDetails(error: unknown): string {\n\tif (error instanceof Error) {\n\t\tconst details: string[] = [`${error.name}: ${error.message}`];\n\t\tconst errorWithCode = error as Error & { code?: string; errno?: number | string; cause?: unknown };\n\t\tif (errorWithCode.code) details.push(`code=${errorWithCode.code}`);\n\t\tif (typeof errorWithCode.errno !== \"undefined\") details.push(`errno=${String(errorWithCode.errno)}`);\n\t\tif (typeof error.cause !== \"undefined\") {\n\t\t\tdetails.push(`cause=${formatErrorDetails(error.cause)}`);\n\t\t}\n\t\tif (error.stack) {\n\t\t\tdetails.push(`stack=${error.stack}`);\n\t\t}\n\t\treturn details.join(\"; \");\n\t}\n\treturn String(error);\n}\n\nasync function startCallbackServer(expectedState: string): Promise<CallbackServerInfo> {\n\tconst { createServer } = await getNodeApis();\n\n\treturn new Promise((resolve, reject) => {\n\t\tlet result: { code: string; state: string } | null = null;\n\t\tlet cancelled = false;\n\n\t\tconst server = createServer((req, res) => {\n\t\t\ttry {\n\t\t\t\tconst url = new URL(req.url || \"\", \"http://localhost\");\n\t\t\t\tif (url.pathname !== CALLBACK_PATH) {\n\t\t\t\t\tres.writeHead(404, { \"Content-Type\": \"text/plain; charset=utf-8\" });\n\t\t\t\t\tres.end(\"Not found\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst code = url.searchParams.get(\"code\");\n\t\t\t\tconst state = url.searchParams.get(\"state\");\n\t\t\t\tconst error = url.searchParams.get(\"error\");\n\n\t\t\t\tif (error) {\n\t\t\t\t\tres.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(`<html><body><h1>Authentication Failed</h1><p>Error: ${error}</p></body></html>`);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!code || !state) {\n\t\t\t\t\tres.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(\n\t\t\t\t\t\t`<html><body><h1>Authentication Failed</h1><p>Missing code or state parameter.</p></body></html>`,\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (state !== expectedState) {\n\t\t\t\t\tres.writeHead(400, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\t\tres.end(`<html><body><h1>Authentication Failed</h1><p>State mismatch.</p></body></html>`);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tres.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" });\n\t\t\t\tres.end(SUCCESS_HTML);\n\t\t\t\tresult = { code, state };\n\t\t\t} catch {\n\t\t\t\tres.writeHead(500, { \"Content-Type\": \"text/plain; charset=utf-8\" });\n\t\t\t\tres.end(\"Internal error\");\n\t\t\t}\n\t\t});\n\n\t\tserver.on(\"error\", (err) => {\n\t\t\treject(err);\n\t\t});\n\n\t\tserver.listen(CALLBACK_PORT, CALLBACK_HOST, () => {\n\t\t\tresolve({\n\t\t\t\tserver,\n\t\t\t\tredirectUri: REDIRECT_URI,\n\t\t\t\tcancelWait: () => {\n\t\t\t\t\tcancelled = true;\n\t\t\t\t},\n\t\t\t\twaitForCode: async () => {\n\t\t\t\t\tconst sleep = () => new Promise((r) => setTimeout(r, 100));\n\t\t\t\t\twhile (!result && !cancelled) {\n\t\t\t\t\t\tawait sleep();\n\t\t\t\t\t}\n\t\t\t\t\treturn result;\n\t\t\t\t},\n\t\t\t});\n\t\t});\n\t});\n}\n\nasync function postJson(url: string, body: Record<string, string | number>): Promise<string> {\n\tconst response = await fetch(url, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t\tAccept: \"application/json\",\n\t\t},\n\t\tbody: JSON.stringify(body),\n\t\tsignal: AbortSignal.timeout(30_000),\n\t});\n\n\tconst responseBody = await response.text();\n\n\tif (!response.ok) {\n\t\tthrow new Error(`HTTP request failed. status=${response.status}; url=${url}; body=${responseBody}`);\n\t}\n\n\treturn responseBody;\n}\n\nasync function exchangeAuthorizationCode(\n\tcode: string,\n\tstate: string,\n\tverifier: string,\n\tredirectUri: string,\n): Promise<OAuthCredentials> {\n\tlet responseBody: string;\n\ttry {\n\t\tresponseBody = await postJson(TOKEN_URL, {\n\t\t\tgrant_type: \"authorization_code\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\tcode,\n\t\t\tstate,\n\t\t\tredirect_uri: redirectUri,\n\t\t\tcode_verifier: verifier,\n\t\t});\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Token exchange request failed. url=${TOKEN_URL}; redirect_uri=${redirectUri}; response_type=authorization_code; details=${formatErrorDetails(error)}`,\n\t\t);\n\t}\n\n\tlet tokenData: { access_token: string; refresh_token: string; expires_in: number };\n\ttry {\n\t\ttokenData = JSON.parse(responseBody) as { access_token: string; refresh_token: string; expires_in: number };\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Token exchange returned invalid JSON. url=${TOKEN_URL}; body=${responseBody}; details=${formatErrorDetails(error)}`,\n\t\t);\n\t}\n\n\treturn {\n\t\trefresh: tokenData.refresh_token,\n\t\taccess: tokenData.access_token,\n\t\texpires: Date.now() + tokenData.expires_in * 1000 - 5 * 60 * 1000,\n\t};\n}\n\n/**\n * Login with Anthropic OAuth (authorization code + PKCE)\n */\nexport async function loginAnthropic(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}): Promise<OAuthCredentials> {\n\tconst { verifier, challenge } = await generatePKCE();\n\tconst server = await startCallbackServer(verifier);\n\n\tlet code: string | undefined;\n\tlet state: string | undefined;\n\tlet redirectUriForExchange = REDIRECT_URI;\n\n\ttry {\n\t\tconst authParams = new URLSearchParams({\n\t\t\tcode: \"true\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\tresponse_type: \"code\",\n\t\t\tredirect_uri: REDIRECT_URI,\n\t\t\tscope: SCOPES,\n\t\t\tcode_challenge: challenge,\n\t\t\tcode_challenge_method: \"S256\",\n\t\t\tstate: verifier,\n\t\t});\n\n\t\toptions.onAuth({\n\t\t\turl: `${AUTHORIZE_URL}?${authParams.toString()}`,\n\t\t\tinstructions:\n\t\t\t\t\"Complete login in your browser. If the browser is on another machine, paste the final redirect URL here.\",\n\t\t});\n\n\t\tif (options.onManualCodeInput) {\n\t\t\tlet manualInput: 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\tmanualInput = 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\n\t\t\tconst result = await server.waitForCode();\n\n\t\t\tif (manualError) {\n\t\t\t\tthrow manualError;\n\t\t\t}\n\n\t\t\tif (result?.code) {\n\t\t\t\tcode = result.code;\n\t\t\t\tstate = result.state;\n\t\t\t\tredirectUriForExchange = REDIRECT_URI;\n\t\t\t} else if (manualInput) {\n\t\t\t\tconst parsed = parseAuthorizationInput(manualInput);\n\t\t\t\tif (parsed.state && parsed.state !== verifier) {\n\t\t\t\t\tthrow new Error(\"OAuth state mismatch\");\n\t\t\t\t}\n\t\t\t\tcode = parsed.code;\n\t\t\t\tstate = parsed.state ?? verifier;\n\t\t\t}\n\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 (manualInput) {\n\t\t\t\t\tconst parsed = parseAuthorizationInput(manualInput);\n\t\t\t\t\tif (parsed.state && parsed.state !== verifier) {\n\t\t\t\t\t\tthrow new Error(\"OAuth state mismatch\");\n\t\t\t\t\t}\n\t\t\t\t\tcode = parsed.code;\n\t\t\t\t\tstate = parsed.state ?? verifier;\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\tstate = result.state;\n\t\t\t\tredirectUriForExchange = REDIRECT_URI;\n\t\t\t}\n\t\t}\n\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\tplaceholder: REDIRECT_URI,\n\t\t\t});\n\t\t\tconst parsed = parseAuthorizationInput(input);\n\t\t\tif (parsed.state && parsed.state !== verifier) {\n\t\t\t\tthrow new Error(\"OAuth state mismatch\");\n\t\t\t}\n\t\t\tcode = parsed.code;\n\t\t\tstate = parsed.state ?? verifier;\n\t\t}\n\n\t\tif (!code) {\n\t\t\tthrow new Error(\"Missing authorization code\");\n\t\t}\n\n\t\tif (!state) {\n\t\t\tthrow new Error(\"Missing OAuth state\");\n\t\t}\n\n\t\toptions.onProgress?.(\"Exchanging authorization code for tokens...\");\n\t\treturn exchangeAuthorizationCode(code, state, verifier, redirectUriForExchange);\n\t} finally {\n\t\tserver.server.close();\n\t}\n}\n\n/**\n * Refresh Anthropic OAuth token\n */\nexport async function refreshAnthropicToken(refreshToken: string): Promise<OAuthCredentials> {\n\tlet responseBody: string;\n\ttry {\n\t\tresponseBody = await postJson(TOKEN_URL, {\n\t\t\tgrant_type: \"refresh_token\",\n\t\t\tclient_id: CLIENT_ID,\n\t\t\trefresh_token: refreshToken,\n\t\t});\n\t} catch (error) {\n\t\tthrow new Error(`Anthropic token refresh request failed. url=${TOKEN_URL}; details=${formatErrorDetails(error)}`);\n\t}\n\n\tlet data: { access_token: string; refresh_token: string; expires_in: number; scope?: string };\n\ttry {\n\t\tdata = JSON.parse(responseBody) as {\n\t\t\taccess_token: string;\n\t\t\trefresh_token: string;\n\t\t\texpires_in: number;\n\t\t\tscope?: string;\n\t\t};\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Anthropic token refresh returned invalid JSON. url=${TOKEN_URL}; body=${responseBody}; details=${formatErrorDetails(error)}`,\n\t\t);\n\t}\n\n\treturn {\n\t\trefresh: data.refresh_token,\n\t\taccess: data.access_token,\n\t\texpires: Date.now() + data.expires_in * 1000 - 5 * 60 * 1000,\n\t};\n}\n\nexport const anthropicOAuthProvider: OAuthProviderInterface = {\n\tid: \"anthropic\",\n\tname: \"Anthropic (Claude Pro/Max)\",\n\tusesCallbackServer: true,\n\n\tasync login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\t\treturn loginAnthropic({\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\n\tasync refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n\t\treturn refreshAnthropicToken(credentials.refresh);\n\t},\n\n\tgetApiKey(credentials: OAuthCredentials): string {\n\t\treturn credentials.access;\n\t},\n};\n"]}
|