@caupulican/pi-ai 0.81.39 → 0.81.41

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.
Files changed (126) hide show
  1. package/dist/env-api-keys.d.ts +5 -0
  2. package/dist/env-api-keys.d.ts.map +1 -1
  3. package/dist/env-api-keys.js +20 -4
  4. package/dist/env-api-keys.js.map +1 -1
  5. package/dist/image-models.generated.d.ts +15 -0
  6. package/dist/image-models.generated.d.ts.map +1 -1
  7. package/dist/image-models.generated.js +15 -0
  8. package/dist/image-models.generated.js.map +1 -1
  9. package/dist/index.d.ts +3 -0
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +3 -0
  12. package/dist/index.js.map +1 -1
  13. package/dist/models.d.ts +7 -0
  14. package/dist/models.d.ts.map +1 -1
  15. package/dist/models.generated.d.ts +1847 -423
  16. package/dist/models.generated.d.ts.map +1 -1
  17. package/dist/models.generated.js +1511 -500
  18. package/dist/models.generated.js.map +1 -1
  19. package/dist/models.js +9 -0
  20. package/dist/models.js.map +1 -1
  21. package/dist/providers/amazon-bedrock.d.ts.map +1 -1
  22. package/dist/providers/amazon-bedrock.js +135 -79
  23. package/dist/providers/amazon-bedrock.js.map +1 -1
  24. package/dist/providers/anthropic.d.ts.map +1 -1
  25. package/dist/providers/anthropic.js +79 -42
  26. package/dist/providers/anthropic.js.map +1 -1
  27. package/dist/providers/azure-openai-responses.d.ts.map +1 -1
  28. package/dist/providers/azure-openai-responses.js +13 -6
  29. package/dist/providers/azure-openai-responses.js.map +1 -1
  30. package/dist/providers/bedrock-sso.d.ts +6 -0
  31. package/dist/providers/bedrock-sso.d.ts.map +1 -0
  32. package/dist/providers/bedrock-sso.js +39 -0
  33. package/dist/providers/bedrock-sso.js.map +1 -0
  34. package/dist/providers/faux.d.ts +1 -0
  35. package/dist/providers/faux.d.ts.map +1 -1
  36. package/dist/providers/faux.js +1 -0
  37. package/dist/providers/faux.js.map +1 -1
  38. package/dist/providers/images/openrouter.d.ts.map +1 -1
  39. package/dist/providers/images/openrouter.js +8 -3
  40. package/dist/providers/images/openrouter.js.map +1 -1
  41. package/dist/providers/mistral.d.ts.map +1 -1
  42. package/dist/providers/mistral.js +20 -15
  43. package/dist/providers/mistral.js.map +1 -1
  44. package/dist/providers/openai-codex-account.d.ts +32 -0
  45. package/dist/providers/openai-codex-account.d.ts.map +1 -0
  46. package/dist/providers/openai-codex-account.js +157 -0
  47. package/dist/providers/openai-codex-account.js.map +1 -0
  48. package/dist/providers/openai-codex-auth.d.ts +11 -0
  49. package/dist/providers/openai-codex-auth.d.ts.map +1 -0
  50. package/dist/providers/openai-codex-auth.js +43 -0
  51. package/dist/providers/openai-codex-auth.js.map +1 -0
  52. package/dist/providers/openai-codex-responses.d.ts +1 -0
  53. package/dist/providers/openai-codex-responses.d.ts.map +1 -1
  54. package/dist/providers/openai-codex-responses.js +97 -72
  55. package/dist/providers/openai-codex-responses.js.map +1 -1
  56. package/dist/providers/openai-completions.d.ts.map +1 -1
  57. package/dist/providers/openai-completions.js +35 -15
  58. package/dist/providers/openai-completions.js.map +1 -1
  59. package/dist/providers/openai-responses-shared.d.ts +5 -0
  60. package/dist/providers/openai-responses-shared.d.ts.map +1 -1
  61. package/dist/providers/openai-responses-shared.js +42 -5
  62. package/dist/providers/openai-responses-shared.js.map +1 -1
  63. package/dist/providers/openai-responses.d.ts +1 -0
  64. package/dist/providers/openai-responses.d.ts.map +1 -1
  65. package/dist/providers/openai-responses.js +28 -9
  66. package/dist/providers/openai-responses.js.map +1 -1
  67. package/dist/providers/openrouter-cache.d.ts +3 -0
  68. package/dist/providers/openrouter-cache.d.ts.map +1 -0
  69. package/dist/providers/openrouter-cache.js +4 -0
  70. package/dist/providers/openrouter-cache.js.map +1 -0
  71. package/dist/providers/simple-options.d.ts.map +1 -1
  72. package/dist/providers/simple-options.js +2 -0
  73. package/dist/providers/simple-options.js.map +1 -1
  74. package/dist/stream.d.ts.map +1 -1
  75. package/dist/stream.js +12 -4
  76. package/dist/stream.js.map +1 -1
  77. package/dist/types.d.ts +27 -4
  78. package/dist/types.d.ts.map +1 -1
  79. package/dist/types.js.map +1 -1
  80. package/dist/utils/abort-signals.d.ts +1 -0
  81. package/dist/utils/abort-signals.d.ts.map +1 -1
  82. package/dist/utils/abort-signals.js +7 -2
  83. package/dist/utils/abort-signals.js.map +1 -1
  84. package/dist/utils/error-body.d.ts.map +1 -1
  85. package/dist/utils/error-body.js +8 -3
  86. package/dist/utils/error-body.js.map +1 -1
  87. package/dist/utils/oauth/index.d.ts +3 -0
  88. package/dist/utils/oauth/index.d.ts.map +1 -1
  89. package/dist/utils/oauth/index.js +9 -0
  90. package/dist/utils/oauth/index.js.map +1 -1
  91. package/dist/utils/oauth/kimi-coding.d.ts +5 -0
  92. package/dist/utils/oauth/kimi-coding.d.ts.map +1 -0
  93. package/dist/utils/oauth/kimi-coding.js +173 -0
  94. package/dist/utils/oauth/kimi-coding.js.map +1 -0
  95. package/dist/utils/oauth/openai-codex.d.ts.map +1 -1
  96. package/dist/utils/oauth/openai-codex.js +2 -21
  97. package/dist/utils/oauth/openai-codex.js.map +1 -1
  98. package/dist/utils/oauth/openrouter.d.ts +5 -0
  99. package/dist/utils/oauth/openrouter.d.ts.map +1 -0
  100. package/dist/utils/oauth/openrouter.js +197 -0
  101. package/dist/utils/oauth/openrouter.js.map +1 -0
  102. package/dist/utils/oauth/xai.d.ts +6 -0
  103. package/dist/utils/oauth/xai.d.ts.map +1 -0
  104. package/dist/utils/oauth/xai.js +154 -0
  105. package/dist/utils/oauth/xai.js.map +1 -0
  106. package/dist/utils/overflow.d.ts +1 -0
  107. package/dist/utils/overflow.d.ts.map +1 -1
  108. package/dist/utils/overflow.js +3 -0
  109. package/dist/utils/overflow.js.map +1 -1
  110. package/dist/utils/provider-retry.d.ts +11 -0
  111. package/dist/utils/provider-retry.d.ts.map +1 -0
  112. package/dist/utils/provider-retry.js +66 -0
  113. package/dist/utils/provider-retry.js.map +1 -0
  114. package/dist/utils/tool-names.d.ts +6 -1
  115. package/dist/utils/tool-names.d.ts.map +1 -1
  116. package/dist/utils/tool-names.js +22 -9
  117. package/dist/utils/tool-names.js.map +1 -1
  118. package/dist/utils/tool-repair/text-protocol.d.ts +3 -0
  119. package/dist/utils/tool-repair/text-protocol.d.ts.map +1 -1
  120. package/dist/utils/tool-repair/text-protocol.js +10 -0
  121. package/dist/utils/tool-repair/text-protocol.js.map +1 -1
  122. package/dist/utils/uuid.d.ts +3 -0
  123. package/dist/utils/uuid.d.ts.map +1 -0
  124. package/dist/utils/uuid.js +48 -0
  125. package/dist/utils/uuid.js.map +1 -0
  126. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"openai-codex.js","sourceRoot":"","sources":["../../../src/utils/oauth/openai-codex.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * OpenAI Codex (ChatGPT OAuth) flow\n *\n * NOTE: This module uses Node.js crypto and http for the OAuth callback.\n * It is only intended for CLI use, not browser environments.\n */\n\n// NEVER convert to top-level imports - breaks browser/Vite builds\nlet _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 { pollOAuthDeviceCodeFlow } from \"./device-code.ts\";\nimport { oauthErrorHtml, oauthSuccessHtml } from \"./oauth-page.ts\";\nimport { generatePKCE } from \"./pkce.ts\";\nimport type {\n\tOAuthCredentials,\n\tOAuthDeviceCodeInfo,\n\tOAuthLoginCallbacks,\n\tOAuthPrompt,\n\tOAuthProviderInterface,\n} from \"./types.ts\";\n\nconst CLIENT_ID = \"app_EMoamEEZ73f0CkXaXp7hrann\";\nconst AUTH_BASE_URL = \"https://auth.openai.com\";\nconst AUTHORIZE_URL = `${AUTH_BASE_URL}/oauth/authorize`;\nconst TOKEN_URL = `${AUTH_BASE_URL}/oauth/token`;\nconst REDIRECT_URI = \"http://localhost:1455/auth/callback\";\nconst DEVICE_USER_CODE_URL = `${AUTH_BASE_URL}/api/accounts/deviceauth/usercode`;\nconst DEVICE_TOKEN_URL = `${AUTH_BASE_URL}/api/accounts/deviceauth/token`;\nconst DEVICE_VERIFICATION_URI = `${AUTH_BASE_URL}/codex/device`;\nconst DEVICE_REDIRECT_URI = `${AUTH_BASE_URL}/deviceauth/callback`;\nconst DEVICE_CODE_TIMEOUT_SECONDS = 15 * 60;\nexport const OPENAI_CODEX_BROWSER_LOGIN_METHOD = \"browser\";\nexport const OPENAI_CODEX_DEVICE_CODE_LOGIN_METHOD = \"device_code\";\nconst SCOPE = \"openid profile email offline_access\";\nconst JWT_CLAIM_PATH = \"https://api.openai.com/auth\";\n\ntype OAuthToken = { access: string; refresh: string; expires: number };\ntype TokenOperation = \"exchange\" | \"refresh\";\nconst TOKEN_EXPIRY_EARLY_REFRESH_MS = 5 * 60 * 1000;\n\nfunction getCallbackHost(): string {\n\treturn typeof process !== \"undefined\" ? process.env.PI_OAUTH_CALLBACK_HOST || \"127.0.0.1\" : \"127.0.0.1\";\n}\n\ntype DeviceAuthInfo = {\n\tdeviceAuthId: string;\n\tuserCode: string;\n\tintervalSeconds: number;\n};\n\ntype DeviceTokenSuccess = {\n\tauthorizationCode: string;\n\tcodeVerifier: string;\n};\n\ntype JwtPayload = {\n\t[JWT_CLAIM_PATH]?: {\n\t\tchatgpt_account_id?: string;\n\t};\n\t[key: string]: unknown;\n};\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}\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 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}\n\nasync function fetchWithLoginCancellation(input: string, init: RequestInit): Promise<Response> {\n\ttry {\n\t\treturn await fetch(input, init);\n\t} catch (error) {\n\t\tif (init.signal?.aborted) {\n\t\t\tthrow new Error(\"Login cancelled\");\n\t\t}\n\t\tthrow error;\n\t}\n}\n\nasync function readTokenResponse(response: Response, operation: TokenOperation): Promise<OAuthToken> {\n\tif (!response.ok) {\n\t\tconst text = await response.text().catch(() => \"\");\n\t\tthrow new Error(`OpenAI Codex token ${operation} failed (${response.status}): ${text || response.statusText}`);\n\t}\n\n\tconst rawJson = await response.json();\n\tconst json = rawJson as {\n\t\taccess_token?: string;\n\t\trefresh_token?: string;\n\t\texpires_in?: number;\n\t} | null;\n\tif (!json?.access_token || !json.refresh_token || typeof json.expires_in !== \"number\") {\n\t\tthrow new Error(`OpenAI Codex token ${operation} response missing fields: ${JSON.stringify(json)}`);\n\t}\n\n\treturn {\n\t\taccess: json.access_token,\n\t\trefresh: json.refresh_token,\n\t\texpires: Date.now() + json.expires_in * 1000 - TOKEN_EXPIRY_EARLY_REFRESH_MS,\n\t};\n}\n\nasync function exchangeAuthorizationCode(\n\tcode: string,\n\tverifier: string,\n\tredirectUri: string = REDIRECT_URI,\n\tsignal?: AbortSignal,\n): Promise<OAuthToken> {\n\tconst response = await fetchWithLoginCancellation(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\tsignal,\n\t});\n\n\treturn readTokenResponse(response, \"exchange\");\n}\n\nasync function refreshAccessToken(refreshToken: string): Promise<OAuthToken> {\n\tlet response: Response;\n\ttry {\n\t\tresponse = 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} catch (error) {\n\t\tthrow new Error(`OpenAI Codex token refresh error: ${error instanceof Error ? error.message : String(error)}`);\n\t}\n\n\treturn readTokenResponse(response, \"refresh\");\n}\n\nasync function startOpenAICodexDeviceAuth(signal?: AbortSignal): Promise<DeviceAuthInfo> {\n\tconst response = await fetchWithLoginCancellation(DEVICE_USER_CODE_URL, {\n\t\tmethod: \"POST\",\n\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\tbody: JSON.stringify({ client_id: CLIENT_ID }),\n\t\tsignal,\n\t});\n\n\tif (!response.ok) {\n\t\tif (response.status === 404) {\n\t\t\tthrow new Error(\n\t\t\t\t\"OpenAI Codex device code login is not enabled for this server. Use browser login or verify the server URL.\",\n\t\t\t);\n\t\t}\n\t\tconst responseBody = await response.text().catch(() => \"\");\n\t\tthrow new Error(\n\t\t\t`OpenAI Codex device code request failed with status ${response.status}${responseBody ? `: ${responseBody}` : \"\"}`,\n\t\t);\n\t}\n\n\tconst rawJson = await response.json();\n\tconst json = rawJson as {\n\t\tdevice_auth_id?: string;\n\t\tuser_code?: string;\n\t\tinterval?: number | string;\n\t} | null;\n\tconst intervalSeconds = typeof json?.interval === \"string\" ? Number(json.interval.trim()) : json?.interval;\n\tif (\n\t\t!json?.device_auth_id ||\n\t\t!json.user_code ||\n\t\ttypeof intervalSeconds !== \"number\" ||\n\t\t!Number.isFinite(intervalSeconds) ||\n\t\tintervalSeconds < 0\n\t) {\n\t\tthrow new Error(`Invalid OpenAI Codex device code response: ${JSON.stringify(json)}`);\n\t}\n\n\treturn {\n\t\tdeviceAuthId: json.device_auth_id,\n\t\tuserCode: json.user_code,\n\t\tintervalSeconds,\n\t};\n}\n\nasync function pollOpenAICodexDeviceAuth(device: DeviceAuthInfo, signal?: AbortSignal): Promise<DeviceTokenSuccess> {\n\treturn pollOAuthDeviceCodeFlow<DeviceTokenSuccess>({\n\t\tintervalSeconds: device.intervalSeconds,\n\t\texpiresInSeconds: DEVICE_CODE_TIMEOUT_SECONDS,\n\t\tsignal,\n\t\tpoll: async () => {\n\t\t\tconst response = await fetchWithLoginCancellation(DEVICE_TOKEN_URL, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tdevice_auth_id: device.deviceAuthId,\n\t\t\t\t\tuser_code: device.userCode,\n\t\t\t\t}),\n\t\t\t\tsignal,\n\t\t\t});\n\n\t\t\tif (response.ok) {\n\t\t\t\tconst rawJson = await response.json();\n\t\t\t\tconst json = rawJson as { authorization_code?: string; code_verifier?: string } | null;\n\t\t\t\tif (!json?.authorization_code || !json.code_verifier) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: \"failed\",\n\t\t\t\t\t\tmessage: `Invalid OpenAI Codex device auth token response: ${JSON.stringify(json)}`,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"complete\",\n\t\t\t\t\tvalue: { authorizationCode: json.authorization_code, codeVerifier: json.code_verifier },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (response.status === 403 || response.status === 404) {\n\t\t\t\treturn { status: \"pending\" };\n\t\t\t}\n\n\t\t\tconst responseBody = await response.text().catch(() => \"\");\n\t\t\tlet errorCode: unknown;\n\t\t\ttry {\n\t\t\t\tconst json = JSON.parse(responseBody) as { error?: string | { code?: string } } | null;\n\t\t\t\tconst error = json?.error;\n\t\t\t\terrorCode = typeof error === \"object\" ? error?.code : error;\n\t\t\t} catch {}\n\n\t\t\tif (errorCode === \"deviceauth_authorization_pending\") {\n\t\t\t\treturn { status: \"pending\" };\n\t\t\t}\n\t\t\tif (errorCode === \"slow_down\") {\n\t\t\t\treturn { status: \"slow_down\" };\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tstatus: \"failed\",\n\t\t\t\tmessage: `OpenAI Codex device auth failed with status ${response.status}${responseBody ? `: ${responseBody}` : \"\"}`,\n\t\t\t};\n\t\t},\n\t});\n}\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\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\n\treturn { verifier, state, url: url.toString() };\n}\n\ntype OAuthServerInfo = {\n\tclose: () => void;\n\tcancelWait: () => void;\n\twaitForCode: () => Promise<{ code: string } | null>;\n};\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\n\tlet settleWait: ((value: { code: string } | null) => void) | undefined;\n\tconst waitForCodePromise = new Promise<{ code: string } | null>((resolve) => {\n\t\tlet settled = false;\n\t\tsettleWait = (value) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tresolve(value);\n\t\t};\n\t});\n\n\tconst server = _http.createServer((req, res) => {\n\t\ttry {\n\t\t\tconst url = new URL(req.url || \"\", \"http://localhost\");\n\t\t\tif (url.pathname !== \"/auth/callback\") {\n\t\t\t\tres.statusCode = 404;\n\t\t\t\tres.setHeader(\"Content-Type\", \"text/html; charset=utf-8\");\n\t\t\t\tres.end(oauthErrorHtml(\"Callback route 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.setHeader(\"Content-Type\", \"text/html; charset=utf-8\");\n\t\t\t\tres.end(oauthErrorHtml(\"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.setHeader(\"Content-Type\", \"text/html; charset=utf-8\");\n\t\t\t\tres.end(oauthErrorHtml(\"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(oauthSuccessHtml(\"OpenAI authentication completed. You can close this window.\"));\n\t\t\tsettleWait?.({ code });\n\t\t} catch {\n\t\t\tres.statusCode = 500;\n\t\t\tres.setHeader(\"Content-Type\", \"text/html; charset=utf-8\");\n\t\t\tres.end(oauthErrorHtml(\"Internal error while processing OAuth callback.\"));\n\t\t}\n\t});\n\n\treturn new Promise((resolve) => {\n\t\tserver\n\t\t\t.listen(1455, getCallbackHost(), () => {\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\tsettleWait?.(null);\n\t\t\t\t\t},\n\t\t\t\t\twaitForCode: () => waitForCodePromise,\n\t\t\t\t});\n\t\t\t})\n\t\t\t.on(\"error\", (_err: NodeJS.ErrnoException) => {\n\t\t\t\tsettleWait?.(null);\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\t\t// ignore\n\t\t\t\t\t\t}\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}\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}\n\nfunction credentialsFromToken(token: OAuthToken): OAuthCredentials {\n\tconst accountId = getAccountId(token.access);\n\tif (!accountId) {\n\t\tthrow new Error(\"Failed to extract accountId from token\");\n\t}\n\n\treturn {\n\t\taccess: token.access,\n\t\trefresh: token.refresh,\n\t\texpires: token.expires,\n\t\taccountId,\n\t};\n}\n\nasync function exchangeAuthorizationCodeForCredentials(\n\tcode: string,\n\tverifier: string,\n\tredirectUri: string,\n\tsignal?: AbortSignal,\n): Promise<OAuthCredentials> {\n\treturn credentialsFromToken(await exchangeAuthorizationCode(code, verifier, redirectUri, signal));\n}\n\n/**\n * Login with OpenAI Codex OAuth using the Codex device-code flow.\n */\nexport async function loginOpenAICodexDeviceCode(options: {\n\tonDeviceCode: (info: OAuthDeviceCodeInfo) => void;\n\tsignal?: AbortSignal;\n}): Promise<OAuthCredentials> {\n\tconst device = await startOpenAICodexDeviceAuth(options.signal);\n\toptions.onDeviceCode({\n\t\tuserCode: device.userCode,\n\t\tverificationUri: DEVICE_VERIFICATION_URI,\n\t\tintervalSeconds: device.intervalSeconds,\n\t\texpiresInSeconds: DEVICE_CODE_TIMEOUT_SECONDS,\n\t});\n\tconst code = await pollOpenAICodexDeviceAuth(device, options.signal);\n\treturn exchangeAuthorizationCodeForCredentials(\n\t\tcode.authorizationCode,\n\t\tcode.codeVerifier,\n\t\tDEVICE_REDIRECT_URI,\n\t\toptions.signal,\n\t);\n}\n\n/**\n * Login with OpenAI Codex OAuth\n *\n * @param options.onAuth - Called with URL and instructions when auth starts\n * @param options.onPrompt - Called to prompt user for manual code paste (fallback if no onManualCodeInput)\n * @param options.onProgress - Optional progress messages\n * @param options.onManualCodeInput - Optional promise that resolves with user-pasted code.\n * Races with browser callback - whichever completes first wins.\n * Useful for showing paste input immediately alongside browser flow.\n * @param options.originator - OAuth originator parameter (defaults to \"pi\")\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\n\toptions.onAuth({ url, instructions: \"A browser window should open. Complete login to finish.\" });\n\n\tlet code: string | undefined;\n\ttry {\n\t\tif (options.onManualCodeInput) {\n\t\t\t// Race between browser callback and manual input\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\n\t\t\tconst result = await server.waitForCode();\n\n\t\t\t// If manual input was cancelled, throw that error\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\t// Browser callback won\n\t\t\t\tcode = result.code;\n\t\t\t} else if (manualCode) {\n\t\t\t\t// Manual input won (or callback timed out and user had entered code)\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\n\t\t\t// If still no code, wait for manual promise to complete and try that\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\t// Original flow: wait for callback, then prompt if needed\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\n\t\t// Fallback to onPrompt if still no code\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\n\t\tif (!code) {\n\t\t\tthrow new Error(\"Missing authorization code\");\n\t\t}\n\n\t\treturn exchangeAuthorizationCodeForCredentials(code, verifier, REDIRECT_URI);\n\t} finally {\n\t\tserver.close();\n\t}\n}\n\n/**\n * Refresh OpenAI Codex OAuth token\n */\nexport async function refreshOpenAICodexToken(refreshToken: string): Promise<OAuthCredentials> {\n\treturn credentialsFromToken(await refreshAccessToken(refreshToken));\n}\n\nexport const openaiCodexOAuthProvider: OAuthProviderInterface = {\n\tid: \"openai-codex\",\n\tname: \"ChatGPT Plus/Pro (Codex Subscription)\",\n\tusesCallbackServer: true,\n\n\tasync login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\t\tconst loginMethod = await callbacks.onSelect({\n\t\t\tmessage: \"Select OpenAI Codex login method:\",\n\t\t\toptions: [\n\t\t\t\t{ id: OPENAI_CODEX_BROWSER_LOGIN_METHOD, label: \"Browser login (default)\" },\n\t\t\t\t{ id: OPENAI_CODEX_DEVICE_CODE_LOGIN_METHOD, label: \"Device code login (headless)\" },\n\t\t\t],\n\t\t});\n\t\tif (!loginMethod) {\n\t\t\tthrow new Error(\"Login cancelled\");\n\t\t}\n\n\t\tif (loginMethod === OPENAI_CODEX_DEVICE_CODE_LOGIN_METHOD) {\n\t\t\treturn loginOpenAICodexDeviceCode({\n\t\t\t\tonDeviceCode: callbacks.onDeviceCode,\n\t\t\t\tsignal: callbacks.signal,\n\t\t\t});\n\t\t}\n\n\t\tif (loginMethod !== OPENAI_CODEX_BROWSER_LOGIN_METHOD) {\n\t\t\tthrow new Error(`Unknown OpenAI Codex login method: ${loginMethod}`);\n\t\t}\n\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\n\tasync refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n\t\treturn refreshOpenAICodexToken(credentials.refresh);\n\t},\n\n\tgetApiKey(credentials: OAuthCredentials): string {\n\t\treturn credentials.access;\n\t},\n};\n"]}
1
+ {"version":3,"file":"openai-codex.js","sourceRoot":"","sources":["../../../src/utils/oauth/openai-codex.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * OpenAI Codex (ChatGPT OAuth) flow\n *\n * NOTE: This module uses Node.js crypto and http for the OAuth callback.\n * It is only intended for CLI use, not browser environments.\n */\n\n// NEVER convert to top-level imports - breaks browser/Vite builds\nlet _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 { getOpenAICodexAccountId } from \"../../providers/openai-codex-auth.ts\";\nimport { pollOAuthDeviceCodeFlow } from \"./device-code.ts\";\nimport { oauthErrorHtml, oauthSuccessHtml } from \"./oauth-page.ts\";\nimport { generatePKCE } from \"./pkce.ts\";\nimport type {\n\tOAuthCredentials,\n\tOAuthDeviceCodeInfo,\n\tOAuthLoginCallbacks,\n\tOAuthPrompt,\n\tOAuthProviderInterface,\n} from \"./types.ts\";\n\nconst CLIENT_ID = \"app_EMoamEEZ73f0CkXaXp7hrann\";\nconst AUTH_BASE_URL = \"https://auth.openai.com\";\nconst AUTHORIZE_URL = `${AUTH_BASE_URL}/oauth/authorize`;\nconst TOKEN_URL = `${AUTH_BASE_URL}/oauth/token`;\nconst REDIRECT_URI = \"http://localhost:1455/auth/callback\";\nconst DEVICE_USER_CODE_URL = `${AUTH_BASE_URL}/api/accounts/deviceauth/usercode`;\nconst DEVICE_TOKEN_URL = `${AUTH_BASE_URL}/api/accounts/deviceauth/token`;\nconst DEVICE_VERIFICATION_URI = `${AUTH_BASE_URL}/codex/device`;\nconst DEVICE_REDIRECT_URI = `${AUTH_BASE_URL}/deviceauth/callback`;\nconst DEVICE_CODE_TIMEOUT_SECONDS = 15 * 60;\nexport const OPENAI_CODEX_BROWSER_LOGIN_METHOD = \"browser\";\nexport const OPENAI_CODEX_DEVICE_CODE_LOGIN_METHOD = \"device_code\";\nconst SCOPE = \"openid profile email offline_access\";\n\ntype OAuthToken = { access: string; refresh: string; expires: number };\ntype TokenOperation = \"exchange\" | \"refresh\";\nconst TOKEN_EXPIRY_EARLY_REFRESH_MS = 5 * 60 * 1000;\n\nfunction getCallbackHost(): string {\n\treturn typeof process !== \"undefined\" ? process.env.PI_OAUTH_CALLBACK_HOST || \"127.0.0.1\" : \"127.0.0.1\";\n}\n\ntype DeviceAuthInfo = {\n\tdeviceAuthId: string;\n\tuserCode: string;\n\tintervalSeconds: number;\n};\n\ntype DeviceTokenSuccess = {\n\tauthorizationCode: string;\n\tcodeVerifier: string;\n};\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}\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\nasync function fetchWithLoginCancellation(input: string, init: RequestInit): Promise<Response> {\n\ttry {\n\t\treturn await fetch(input, init);\n\t} catch (error) {\n\t\tif (init.signal?.aborted) {\n\t\t\tthrow new Error(\"Login cancelled\");\n\t\t}\n\t\tthrow error;\n\t}\n}\n\nasync function readTokenResponse(response: Response, operation: TokenOperation): Promise<OAuthToken> {\n\tif (!response.ok) {\n\t\tconst text = await response.text().catch(() => \"\");\n\t\tthrow new Error(`OpenAI Codex token ${operation} failed (${response.status}): ${text || response.statusText}`);\n\t}\n\n\tconst rawJson = await response.json();\n\tconst json = rawJson as {\n\t\taccess_token?: string;\n\t\trefresh_token?: string;\n\t\texpires_in?: number;\n\t} | null;\n\tif (!json?.access_token || !json.refresh_token || typeof json.expires_in !== \"number\") {\n\t\tthrow new Error(`OpenAI Codex token ${operation} response missing fields: ${JSON.stringify(json)}`);\n\t}\n\n\treturn {\n\t\taccess: json.access_token,\n\t\trefresh: json.refresh_token,\n\t\texpires: Date.now() + json.expires_in * 1000 - TOKEN_EXPIRY_EARLY_REFRESH_MS,\n\t};\n}\n\nasync function exchangeAuthorizationCode(\n\tcode: string,\n\tverifier: string,\n\tredirectUri: string = REDIRECT_URI,\n\tsignal?: AbortSignal,\n): Promise<OAuthToken> {\n\tconst response = await fetchWithLoginCancellation(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\tsignal,\n\t});\n\n\treturn readTokenResponse(response, \"exchange\");\n}\n\nasync function refreshAccessToken(refreshToken: string): Promise<OAuthToken> {\n\tlet response: Response;\n\ttry {\n\t\tresponse = 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} catch (error) {\n\t\tthrow new Error(`OpenAI Codex token refresh error: ${error instanceof Error ? error.message : String(error)}`);\n\t}\n\n\treturn readTokenResponse(response, \"refresh\");\n}\n\nasync function startOpenAICodexDeviceAuth(signal?: AbortSignal): Promise<DeviceAuthInfo> {\n\tconst response = await fetchWithLoginCancellation(DEVICE_USER_CODE_URL, {\n\t\tmethod: \"POST\",\n\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\tbody: JSON.stringify({ client_id: CLIENT_ID }),\n\t\tsignal,\n\t});\n\n\tif (!response.ok) {\n\t\tif (response.status === 404) {\n\t\t\tthrow new Error(\n\t\t\t\t\"OpenAI Codex device code login is not enabled for this server. Use browser login or verify the server URL.\",\n\t\t\t);\n\t\t}\n\t\tconst responseBody = await response.text().catch(() => \"\");\n\t\tthrow new Error(\n\t\t\t`OpenAI Codex device code request failed with status ${response.status}${responseBody ? `: ${responseBody}` : \"\"}`,\n\t\t);\n\t}\n\n\tconst rawJson = await response.json();\n\tconst json = rawJson as {\n\t\tdevice_auth_id?: string;\n\t\tuser_code?: string;\n\t\tinterval?: number | string;\n\t} | null;\n\tconst intervalSeconds = typeof json?.interval === \"string\" ? Number(json.interval.trim()) : json?.interval;\n\tif (\n\t\t!json?.device_auth_id ||\n\t\t!json.user_code ||\n\t\ttypeof intervalSeconds !== \"number\" ||\n\t\t!Number.isFinite(intervalSeconds) ||\n\t\tintervalSeconds < 0\n\t) {\n\t\tthrow new Error(`Invalid OpenAI Codex device code response: ${JSON.stringify(json)}`);\n\t}\n\n\treturn {\n\t\tdeviceAuthId: json.device_auth_id,\n\t\tuserCode: json.user_code,\n\t\tintervalSeconds,\n\t};\n}\n\nasync function pollOpenAICodexDeviceAuth(device: DeviceAuthInfo, signal?: AbortSignal): Promise<DeviceTokenSuccess> {\n\treturn pollOAuthDeviceCodeFlow<DeviceTokenSuccess>({\n\t\tintervalSeconds: device.intervalSeconds,\n\t\texpiresInSeconds: DEVICE_CODE_TIMEOUT_SECONDS,\n\t\tsignal,\n\t\tpoll: async () => {\n\t\t\tconst response = await fetchWithLoginCancellation(DEVICE_TOKEN_URL, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tdevice_auth_id: device.deviceAuthId,\n\t\t\t\t\tuser_code: device.userCode,\n\t\t\t\t}),\n\t\t\t\tsignal,\n\t\t\t});\n\n\t\t\tif (response.ok) {\n\t\t\t\tconst rawJson = await response.json();\n\t\t\t\tconst json = rawJson as { authorization_code?: string; code_verifier?: string } | null;\n\t\t\t\tif (!json?.authorization_code || !json.code_verifier) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: \"failed\",\n\t\t\t\t\t\tmessage: `Invalid OpenAI Codex device auth token response: ${JSON.stringify(json)}`,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"complete\",\n\t\t\t\t\tvalue: { authorizationCode: json.authorization_code, codeVerifier: json.code_verifier },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (response.status === 403 || response.status === 404) {\n\t\t\t\treturn { status: \"pending\" };\n\t\t\t}\n\n\t\t\tconst responseBody = await response.text().catch(() => \"\");\n\t\t\tlet errorCode: unknown;\n\t\t\ttry {\n\t\t\t\tconst json = JSON.parse(responseBody) as { error?: string | { code?: string } } | null;\n\t\t\t\tconst error = json?.error;\n\t\t\t\terrorCode = typeof error === \"object\" ? error?.code : error;\n\t\t\t} catch {}\n\n\t\t\tif (errorCode === \"deviceauth_authorization_pending\") {\n\t\t\t\treturn { status: \"pending\" };\n\t\t\t}\n\t\t\tif (errorCode === \"slow_down\") {\n\t\t\t\treturn { status: \"slow_down\" };\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tstatus: \"failed\",\n\t\t\t\tmessage: `OpenAI Codex device auth failed with status ${response.status}${responseBody ? `: ${responseBody}` : \"\"}`,\n\t\t\t};\n\t\t},\n\t});\n}\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\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\n\treturn { verifier, state, url: url.toString() };\n}\n\ntype OAuthServerInfo = {\n\tclose: () => void;\n\tcancelWait: () => void;\n\twaitForCode: () => Promise<{ code: string } | null>;\n};\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\n\tlet settleWait: ((value: { code: string } | null) => void) | undefined;\n\tconst waitForCodePromise = new Promise<{ code: string } | null>((resolve) => {\n\t\tlet settled = false;\n\t\tsettleWait = (value) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tresolve(value);\n\t\t};\n\t});\n\n\tconst server = _http.createServer((req, res) => {\n\t\ttry {\n\t\t\tconst url = new URL(req.url || \"\", \"http://localhost\");\n\t\t\tif (url.pathname !== \"/auth/callback\") {\n\t\t\t\tres.statusCode = 404;\n\t\t\t\tres.setHeader(\"Content-Type\", \"text/html; charset=utf-8\");\n\t\t\t\tres.end(oauthErrorHtml(\"Callback route 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.setHeader(\"Content-Type\", \"text/html; charset=utf-8\");\n\t\t\t\tres.end(oauthErrorHtml(\"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.setHeader(\"Content-Type\", \"text/html; charset=utf-8\");\n\t\t\t\tres.end(oauthErrorHtml(\"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(oauthSuccessHtml(\"OpenAI authentication completed. You can close this window.\"));\n\t\t\tsettleWait?.({ code });\n\t\t} catch {\n\t\t\tres.statusCode = 500;\n\t\t\tres.setHeader(\"Content-Type\", \"text/html; charset=utf-8\");\n\t\t\tres.end(oauthErrorHtml(\"Internal error while processing OAuth callback.\"));\n\t\t}\n\t});\n\n\treturn new Promise((resolve) => {\n\t\tserver\n\t\t\t.listen(1455, getCallbackHost(), () => {\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\tsettleWait?.(null);\n\t\t\t\t\t},\n\t\t\t\t\twaitForCode: () => waitForCodePromise,\n\t\t\t\t});\n\t\t\t})\n\t\t\t.on(\"error\", (_err: NodeJS.ErrnoException) => {\n\t\t\t\tsettleWait?.(null);\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\t\t// ignore\n\t\t\t\t\t\t}\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}\n\nfunction credentialsFromToken(token: OAuthToken): OAuthCredentials {\n\tconst accountId = getOpenAICodexAccountId(token.access);\n\tif (!accountId) {\n\t\tthrow new Error(\"Failed to extract accountId from token\");\n\t}\n\n\treturn {\n\t\taccess: token.access,\n\t\trefresh: token.refresh,\n\t\texpires: token.expires,\n\t\taccountId,\n\t};\n}\n\nasync function exchangeAuthorizationCodeForCredentials(\n\tcode: string,\n\tverifier: string,\n\tredirectUri: string,\n\tsignal?: AbortSignal,\n): Promise<OAuthCredentials> {\n\treturn credentialsFromToken(await exchangeAuthorizationCode(code, verifier, redirectUri, signal));\n}\n\n/**\n * Login with OpenAI Codex OAuth using the Codex device-code flow.\n */\nexport async function loginOpenAICodexDeviceCode(options: {\n\tonDeviceCode: (info: OAuthDeviceCodeInfo) => void;\n\tsignal?: AbortSignal;\n}): Promise<OAuthCredentials> {\n\tconst device = await startOpenAICodexDeviceAuth(options.signal);\n\toptions.onDeviceCode({\n\t\tuserCode: device.userCode,\n\t\tverificationUri: DEVICE_VERIFICATION_URI,\n\t\tintervalSeconds: device.intervalSeconds,\n\t\texpiresInSeconds: DEVICE_CODE_TIMEOUT_SECONDS,\n\t});\n\tconst code = await pollOpenAICodexDeviceAuth(device, options.signal);\n\treturn exchangeAuthorizationCodeForCredentials(\n\t\tcode.authorizationCode,\n\t\tcode.codeVerifier,\n\t\tDEVICE_REDIRECT_URI,\n\t\toptions.signal,\n\t);\n}\n\n/**\n * Login with OpenAI Codex OAuth\n *\n * @param options.onAuth - Called with URL and instructions when auth starts\n * @param options.onPrompt - Called to prompt user for manual code paste (fallback if no onManualCodeInput)\n * @param options.onProgress - Optional progress messages\n * @param options.onManualCodeInput - Optional promise that resolves with user-pasted code.\n * Races with browser callback - whichever completes first wins.\n * Useful for showing paste input immediately alongside browser flow.\n * @param options.originator - OAuth originator parameter (defaults to \"pi\")\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\n\toptions.onAuth({ url, instructions: \"A browser window should open. Complete login to finish.\" });\n\n\tlet code: string | undefined;\n\ttry {\n\t\tif (options.onManualCodeInput) {\n\t\t\t// Race between browser callback and manual input\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\n\t\t\tconst result = await server.waitForCode();\n\n\t\t\t// If manual input was cancelled, throw that error\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\t// Browser callback won\n\t\t\t\tcode = result.code;\n\t\t\t} else if (manualCode) {\n\t\t\t\t// Manual input won (or callback timed out and user had entered code)\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\n\t\t\t// If still no code, wait for manual promise to complete and try that\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\t// Original flow: wait for callback, then prompt if needed\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\n\t\t// Fallback to onPrompt if still no code\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\n\t\tif (!code) {\n\t\t\tthrow new Error(\"Missing authorization code\");\n\t\t}\n\n\t\treturn exchangeAuthorizationCodeForCredentials(code, verifier, REDIRECT_URI);\n\t} finally {\n\t\tserver.close();\n\t}\n}\n\n/**\n * Refresh OpenAI Codex OAuth token\n */\nexport async function refreshOpenAICodexToken(refreshToken: string): Promise<OAuthCredentials> {\n\treturn credentialsFromToken(await refreshAccessToken(refreshToken));\n}\n\nexport const openaiCodexOAuthProvider: OAuthProviderInterface = {\n\tid: \"openai-codex\",\n\tname: \"ChatGPT Plus/Pro (Codex Subscription)\",\n\tusesCallbackServer: true,\n\n\tasync login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\t\tconst loginMethod = await callbacks.onSelect({\n\t\t\tmessage: \"Select OpenAI Codex login method:\",\n\t\t\toptions: [\n\t\t\t\t{ id: OPENAI_CODEX_BROWSER_LOGIN_METHOD, label: \"Browser login (default)\" },\n\t\t\t\t{ id: OPENAI_CODEX_DEVICE_CODE_LOGIN_METHOD, label: \"Device code login (headless)\" },\n\t\t\t],\n\t\t});\n\t\tif (!loginMethod) {\n\t\t\tthrow new Error(\"Login cancelled\");\n\t\t}\n\n\t\tif (loginMethod === OPENAI_CODEX_DEVICE_CODE_LOGIN_METHOD) {\n\t\t\treturn loginOpenAICodexDeviceCode({\n\t\t\t\tonDeviceCode: callbacks.onDeviceCode,\n\t\t\t\tsignal: callbacks.signal,\n\t\t\t});\n\t\t}\n\n\t\tif (loginMethod !== OPENAI_CODEX_BROWSER_LOGIN_METHOD) {\n\t\t\tthrow new Error(`Unknown OpenAI Codex login method: ${loginMethod}`);\n\t\t}\n\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\n\tasync refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n\t\treturn refreshOpenAICodexToken(credentials.refresh);\n\t},\n\n\tgetApiKey(credentials: OAuthCredentials): string {\n\t\treturn credentials.access;\n\t},\n};\n"]}
@@ -0,0 +1,5 @@
1
+ /** OpenRouter OAuth PKCE flow. */
2
+ import type { OAuthCredentials, OAuthLoginCallbacks, OAuthProviderInterface } from "./types.ts";
3
+ export declare function loginOpenRouter(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials>;
4
+ export declare const openRouterOAuthProvider: OAuthProviderInterface;
5
+ //# sourceMappingURL=openrouter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openrouter.d.ts","sourceRoot":"","sources":["../../../src/utils/oauth/openrouter.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAMlC,OAAO,KAAK,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAsLhG,wBAAsB,eAAe,CAAC,SAAS,EAAE,mBAAmB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAiB/F;AAED,eAAO,MAAM,uBAAuB,EAAE,sBAOrC,CAAC","sourcesContent":["/** OpenRouter OAuth PKCE flow. */\n\nimport { randomUUID } from \"node:crypto\";\nimport { createServer, type ServerResponse } from \"node:http\";\nimport { oauthErrorHtml, oauthSuccessHtml } from \"./oauth-page.ts\";\nimport { generatePKCE } from \"./pkce.ts\";\nimport type { OAuthCredentials, OAuthLoginCallbacks, OAuthProviderInterface } from \"./types.ts\";\n\nconst AUTHORIZE_URL = \"https://openrouter.ai/auth\";\nconst TOKEN_URL = \"https://openrouter.ai/api/v1/auth/keys\";\nconst LOGIN_TIMEOUT_MS = 5 * 60 * 1000;\nconst TOKEN_EXCHANGE_TIMEOUT_MS = 30_000;\n\ntype JsonObject = Record<string, unknown>;\n\ntype OpenRouterCallbackServer = {\n\tcallbackUrl: string;\n\tcredential: Promise<OAuthCredentials>;\n\tclose(): void;\n};\n\nfunction getCallbackHost(): string {\n\treturn process.env.PI_OAUTH_CALLBACK_HOST || \"127.0.0.1\";\n}\n\nfunction sendHtml(response: ServerResponse, status: number, html: string): void {\n\tresponse.statusCode = status;\n\tresponse.setHeader(\"content-type\", \"text/html; charset=utf-8\");\n\tresponse.setHeader(\"cache-control\", \"no-store\");\n\tresponse.end(html);\n}\n\nfunction errorDetail(body: JsonObject): string | undefined {\n\tif (typeof body.error_description === \"string\") return body.error_description;\n\tif (typeof body.message === \"string\") return body.message;\n\tif (typeof body.error === \"string\") return body.error;\n\tif (body.error && typeof body.error === \"object\" && !Array.isArray(body.error)) {\n\t\tconst message = (body.error as JsonObject).message;\n\t\tif (typeof message === \"string\") return message;\n\t}\n\treturn undefined;\n}\n\nasync function exchangeAuthorizationCode(\n\tcode: string,\n\tverifier: string,\n\tsignal?: AbortSignal,\n): Promise<OAuthCredentials> {\n\tif (signal?.aborted) throw new Error(\"Login cancelled\");\n\tconst controller = new AbortController();\n\tconst onAbort = () => controller.abort(signal?.reason);\n\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\tconst timeout = setTimeout(\n\t\t() => controller.abort(new Error(\"OpenRouter OAuth token exchange timed out\")),\n\t\tTOKEN_EXCHANGE_TIMEOUT_MS,\n\t);\n\n\tlet response: Response;\n\tlet body: JsonObject = {};\n\ttry {\n\t\tresponse = await fetch(TOKEN_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { accept: \"application/json\", \"content-type\": \"application/json\" },\n\t\t\tbody: JSON.stringify({ code, code_verifier: verifier, code_challenge_method: \"S256\" }),\n\t\t\tsignal: controller.signal,\n\t\t});\n\t\ttry {\n\t\t\tconst parsed = (await response.json()) as unknown;\n\t\t\tif (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) body = parsed as JsonObject;\n\t\t} catch {\n\t\t\tif (response.ok) throw new Error(\"OpenRouter OAuth returned invalid JSON\");\n\t\t}\n\t} catch (error) {\n\t\tif (signal?.aborted) throw new Error(\"Login cancelled\");\n\t\tif (controller.signal.aborted) throw new Error(\"OpenRouter OAuth token exchange timed out\");\n\t\tthrow error;\n\t} finally {\n\t\tclearTimeout(timeout);\n\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t}\n\n\tif (!response.ok) {\n\t\tconst detail = errorDetail(body);\n\t\tthrow new Error(`OpenRouter OAuth key exchange failed (HTTP ${response.status})${detail ? `: ${detail}` : \"\"}`);\n\t}\n\tif (typeof body.key !== \"string\" || body.key.length === 0) {\n\t\tthrow new Error('OpenRouter OAuth response carries no \"key\"');\n\t}\n\treturn { access: body.key, refresh: \"\", expires: Number.MAX_SAFE_INTEGER };\n}\n\nasync function startCallbackServer(\n\tcallbackPath: string,\n\tverifier: string,\n\tsignal?: AbortSignal,\n): Promise<OpenRouterCallbackServer> {\n\tif (signal?.aborted) throw new Error(\"Login cancelled\");\n\tconst callbackHost = getCallbackHost();\n\tlet resolveCredential: (credential: OAuthCredentials) => void = () => {};\n\tlet rejectCredential: (error: Error) => void = () => {};\n\tconst credential = new Promise<OAuthCredentials>((resolve, reject) => {\n\t\tresolveCredential = resolve;\n\t\trejectCredential = reject;\n\t});\n\n\tlet claimed = false;\n\tlet settled = false;\n\tlet timeout: ReturnType<typeof setTimeout> | undefined;\n\tlet onAbort: (() => void) | undefined;\n\tconst server = createServer((request, response) => {\n\t\tvoid (async () => {\n\t\t\tconst requestUrl = new URL(request.url ?? \"/\", `http://${callbackHost}`);\n\t\t\tif (request.method !== \"GET\" || requestUrl.pathname !== callbackPath) {\n\t\t\t\tsendHtml(response, 404, oauthErrorHtml(\"OAuth callback route not found.\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (claimed || settled) {\n\t\t\t\tsendHtml(response, 409, oauthErrorHtml(\"This OAuth callback has already been used.\"));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst oauthError = requestUrl.searchParams.get(\"error\");\n\t\t\tif (oauthError) {\n\t\t\t\tconst description = requestUrl.searchParams.get(\"error_description\") ?? oauthError;\n\t\t\t\tsendHtml(response, 400, oauthErrorHtml(\"OpenRouter authorization was denied.\", description));\n\t\t\t\tfinish({ error: new Error(`OpenRouter authorization failed: ${description}`) });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst code = requestUrl.searchParams.get(\"code\");\n\t\t\tif (!code) {\n\t\t\t\tsendHtml(response, 400, oauthErrorHtml(\"OpenRouter returned no authorization code.\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tclaimed = true;\n\n\t\t\ttry {\n\t\t\t\tconst result = await exchangeAuthorizationCode(code, verifier, signal);\n\t\t\t\tsendHtml(response, 200, oauthSuccessHtml(\"Signed in to OpenRouter. You may now close this page.\"));\n\t\t\t\tfinish({ credential: result });\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : \"Unknown token exchange error\";\n\t\t\t\tsendHtml(response, 502, oauthErrorHtml(\"OpenRouter key exchange failed.\", message));\n\t\t\t\tfinish({ error: error instanceof Error ? error : new Error(message) });\n\t\t\t}\n\t\t})();\n\t});\n\n\tconst finish = (result: { credential: OAuthCredentials } | { error: Error }): void => {\n\t\tif (settled) return;\n\t\tsettled = true;\n\t\tif (timeout) clearTimeout(timeout);\n\t\tif (onAbort) signal?.removeEventListener(\"abort\", onAbort);\n\t\tserver.close();\n\t\tif (\"credential\" in result) resolveCredential(result.credential);\n\t\telse rejectCredential(result.error);\n\t};\n\n\tawait new Promise<void>((resolve, reject) => {\n\t\tserver.once(\"error\", reject);\n\t\tserver.listen(0, callbackHost, () => {\n\t\t\tserver.removeListener(\"error\", reject);\n\t\t\tresolve();\n\t\t});\n\t});\n\n\tserver.on(\"error\", (error) => finish({ error }));\n\tonAbort = () => finish({ error: new Error(\"Login cancelled\") });\n\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\tif (signal?.aborted) {\n\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\tserver.close();\n\t\tthrow new Error(\"Login cancelled\");\n\t}\n\ttimeout = setTimeout(() => finish({ error: new Error(\"OpenRouter OAuth login timed out\") }), LOGIN_TIMEOUT_MS);\n\n\tconst address = server.address();\n\tif (!address || typeof address === \"string\") {\n\t\tfinish({ error: new Error(\"Could not determine the OpenRouter OAuth callback port\") });\n\t\tthrow new Error(\"Could not determine the OpenRouter OAuth callback port\");\n\t}\n\treturn {\n\t\tcallbackUrl: `http://${callbackHost}:${address.port}${callbackPath}`,\n\t\tcredential,\n\t\tclose: () => finish({ error: new Error(\"Login cancelled\") }),\n\t};\n}\n\nexport async function loginOpenRouter(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\tconst { verifier, challenge } = await generatePKCE();\n\tconst callbackPath = `/oauth/callback/${randomUUID()}`;\n\tconst callback = await startCallbackServer(callbackPath, verifier, callbacks.signal);\n\tconst authorizeUrl = new URL(AUTHORIZE_URL);\n\tauthorizeUrl.search = new URLSearchParams({\n\t\tcallback_url: callback.callbackUrl,\n\t\tcode_challenge: challenge,\n\t\tcode_challenge_method: \"S256\",\n\t}).toString();\n\tcallbacks.onProgress?.(`Listening for OpenRouter OAuth callback on ${callback.callbackUrl}`);\n\tcallbacks.onAuth({ url: authorizeUrl.toString(), instructions: \"Complete sign-in in your browser.\" });\n\ttry {\n\t\treturn await callback.credential;\n\t} finally {\n\t\tcallback.close();\n\t}\n}\n\nexport const openRouterOAuthProvider: OAuthProviderInterface = {\n\tid: \"openrouter\",\n\tname: \"OpenRouter OAuth\",\n\tusesCallbackServer: true,\n\tlogin: loginOpenRouter,\n\trefreshToken: async (credentials) => credentials,\n\tgetApiKey: (credentials) => credentials.access,\n};\n"]}
@@ -0,0 +1,197 @@
1
+ /** OpenRouter OAuth PKCE flow. */
2
+ import { randomUUID } from "node:crypto";
3
+ import { createServer } from "node:http";
4
+ import { oauthErrorHtml, oauthSuccessHtml } from "./oauth-page.js";
5
+ import { generatePKCE } from "./pkce.js";
6
+ const AUTHORIZE_URL = "https://openrouter.ai/auth";
7
+ const TOKEN_URL = "https://openrouter.ai/api/v1/auth/keys";
8
+ const LOGIN_TIMEOUT_MS = 5 * 60 * 1000;
9
+ const TOKEN_EXCHANGE_TIMEOUT_MS = 30_000;
10
+ function getCallbackHost() {
11
+ return process.env.PI_OAUTH_CALLBACK_HOST || "127.0.0.1";
12
+ }
13
+ function sendHtml(response, status, html) {
14
+ response.statusCode = status;
15
+ response.setHeader("content-type", "text/html; charset=utf-8");
16
+ response.setHeader("cache-control", "no-store");
17
+ response.end(html);
18
+ }
19
+ function errorDetail(body) {
20
+ if (typeof body.error_description === "string")
21
+ return body.error_description;
22
+ if (typeof body.message === "string")
23
+ return body.message;
24
+ if (typeof body.error === "string")
25
+ return body.error;
26
+ if (body.error && typeof body.error === "object" && !Array.isArray(body.error)) {
27
+ const message = body.error.message;
28
+ if (typeof message === "string")
29
+ return message;
30
+ }
31
+ return undefined;
32
+ }
33
+ async function exchangeAuthorizationCode(code, verifier, signal) {
34
+ if (signal?.aborted)
35
+ throw new Error("Login cancelled");
36
+ const controller = new AbortController();
37
+ const onAbort = () => controller.abort(signal?.reason);
38
+ signal?.addEventListener("abort", onAbort, { once: true });
39
+ const timeout = setTimeout(() => controller.abort(new Error("OpenRouter OAuth token exchange timed out")), TOKEN_EXCHANGE_TIMEOUT_MS);
40
+ let response;
41
+ let body = {};
42
+ try {
43
+ response = await fetch(TOKEN_URL, {
44
+ method: "POST",
45
+ headers: { accept: "application/json", "content-type": "application/json" },
46
+ body: JSON.stringify({ code, code_verifier: verifier, code_challenge_method: "S256" }),
47
+ signal: controller.signal,
48
+ });
49
+ try {
50
+ const parsed = (await response.json());
51
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed))
52
+ body = parsed;
53
+ }
54
+ catch {
55
+ if (response.ok)
56
+ throw new Error("OpenRouter OAuth returned invalid JSON");
57
+ }
58
+ }
59
+ catch (error) {
60
+ if (signal?.aborted)
61
+ throw new Error("Login cancelled");
62
+ if (controller.signal.aborted)
63
+ throw new Error("OpenRouter OAuth token exchange timed out");
64
+ throw error;
65
+ }
66
+ finally {
67
+ clearTimeout(timeout);
68
+ signal?.removeEventListener("abort", onAbort);
69
+ }
70
+ if (!response.ok) {
71
+ const detail = errorDetail(body);
72
+ throw new Error(`OpenRouter OAuth key exchange failed (HTTP ${response.status})${detail ? `: ${detail}` : ""}`);
73
+ }
74
+ if (typeof body.key !== "string" || body.key.length === 0) {
75
+ throw new Error('OpenRouter OAuth response carries no "key"');
76
+ }
77
+ return { access: body.key, refresh: "", expires: Number.MAX_SAFE_INTEGER };
78
+ }
79
+ async function startCallbackServer(callbackPath, verifier, signal) {
80
+ if (signal?.aborted)
81
+ throw new Error("Login cancelled");
82
+ const callbackHost = getCallbackHost();
83
+ let resolveCredential = () => { };
84
+ let rejectCredential = () => { };
85
+ const credential = new Promise((resolve, reject) => {
86
+ resolveCredential = resolve;
87
+ rejectCredential = reject;
88
+ });
89
+ let claimed = false;
90
+ let settled = false;
91
+ let timeout;
92
+ let onAbort;
93
+ const server = createServer((request, response) => {
94
+ void (async () => {
95
+ const requestUrl = new URL(request.url ?? "/", `http://${callbackHost}`);
96
+ if (request.method !== "GET" || requestUrl.pathname !== callbackPath) {
97
+ sendHtml(response, 404, oauthErrorHtml("OAuth callback route not found."));
98
+ return;
99
+ }
100
+ if (claimed || settled) {
101
+ sendHtml(response, 409, oauthErrorHtml("This OAuth callback has already been used."));
102
+ return;
103
+ }
104
+ const oauthError = requestUrl.searchParams.get("error");
105
+ if (oauthError) {
106
+ const description = requestUrl.searchParams.get("error_description") ?? oauthError;
107
+ sendHtml(response, 400, oauthErrorHtml("OpenRouter authorization was denied.", description));
108
+ finish({ error: new Error(`OpenRouter authorization failed: ${description}`) });
109
+ return;
110
+ }
111
+ const code = requestUrl.searchParams.get("code");
112
+ if (!code) {
113
+ sendHtml(response, 400, oauthErrorHtml("OpenRouter returned no authorization code."));
114
+ return;
115
+ }
116
+ claimed = true;
117
+ try {
118
+ const result = await exchangeAuthorizationCode(code, verifier, signal);
119
+ sendHtml(response, 200, oauthSuccessHtml("Signed in to OpenRouter. You may now close this page."));
120
+ finish({ credential: result });
121
+ }
122
+ catch (error) {
123
+ const message = error instanceof Error ? error.message : "Unknown token exchange error";
124
+ sendHtml(response, 502, oauthErrorHtml("OpenRouter key exchange failed.", message));
125
+ finish({ error: error instanceof Error ? error : new Error(message) });
126
+ }
127
+ })();
128
+ });
129
+ const finish = (result) => {
130
+ if (settled)
131
+ return;
132
+ settled = true;
133
+ if (timeout)
134
+ clearTimeout(timeout);
135
+ if (onAbort)
136
+ signal?.removeEventListener("abort", onAbort);
137
+ server.close();
138
+ if ("credential" in result)
139
+ resolveCredential(result.credential);
140
+ else
141
+ rejectCredential(result.error);
142
+ };
143
+ await new Promise((resolve, reject) => {
144
+ server.once("error", reject);
145
+ server.listen(0, callbackHost, () => {
146
+ server.removeListener("error", reject);
147
+ resolve();
148
+ });
149
+ });
150
+ server.on("error", (error) => finish({ error }));
151
+ onAbort = () => finish({ error: new Error("Login cancelled") });
152
+ signal?.addEventListener("abort", onAbort, { once: true });
153
+ if (signal?.aborted) {
154
+ signal.removeEventListener("abort", onAbort);
155
+ server.close();
156
+ throw new Error("Login cancelled");
157
+ }
158
+ timeout = setTimeout(() => finish({ error: new Error("OpenRouter OAuth login timed out") }), LOGIN_TIMEOUT_MS);
159
+ const address = server.address();
160
+ if (!address || typeof address === "string") {
161
+ finish({ error: new Error("Could not determine the OpenRouter OAuth callback port") });
162
+ throw new Error("Could not determine the OpenRouter OAuth callback port");
163
+ }
164
+ return {
165
+ callbackUrl: `http://${callbackHost}:${address.port}${callbackPath}`,
166
+ credential,
167
+ close: () => finish({ error: new Error("Login cancelled") }),
168
+ };
169
+ }
170
+ export async function loginOpenRouter(callbacks) {
171
+ const { verifier, challenge } = await generatePKCE();
172
+ const callbackPath = `/oauth/callback/${randomUUID()}`;
173
+ const callback = await startCallbackServer(callbackPath, verifier, callbacks.signal);
174
+ const authorizeUrl = new URL(AUTHORIZE_URL);
175
+ authorizeUrl.search = new URLSearchParams({
176
+ callback_url: callback.callbackUrl,
177
+ code_challenge: challenge,
178
+ code_challenge_method: "S256",
179
+ }).toString();
180
+ callbacks.onProgress?.(`Listening for OpenRouter OAuth callback on ${callback.callbackUrl}`);
181
+ callbacks.onAuth({ url: authorizeUrl.toString(), instructions: "Complete sign-in in your browser." });
182
+ try {
183
+ return await callback.credential;
184
+ }
185
+ finally {
186
+ callback.close();
187
+ }
188
+ }
189
+ export const openRouterOAuthProvider = {
190
+ id: "openrouter",
191
+ name: "OpenRouter OAuth",
192
+ usesCallbackServer: true,
193
+ login: loginOpenRouter,
194
+ refreshToken: async (credentials) => credentials,
195
+ getApiKey: (credentials) => credentials.access,
196
+ };
197
+ //# sourceMappingURL=openrouter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openrouter.js","sourceRoot":"","sources":["../../../src/utils/oauth/openrouter.ts"],"names":[],"mappings":"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","sourcesContent":["/** OpenRouter OAuth PKCE flow. */\n\nimport { randomUUID } from \"node:crypto\";\nimport { createServer, type ServerResponse } from \"node:http\";\nimport { oauthErrorHtml, oauthSuccessHtml } from \"./oauth-page.ts\";\nimport { generatePKCE } from \"./pkce.ts\";\nimport type { OAuthCredentials, OAuthLoginCallbacks, OAuthProviderInterface } from \"./types.ts\";\n\nconst AUTHORIZE_URL = \"https://openrouter.ai/auth\";\nconst TOKEN_URL = \"https://openrouter.ai/api/v1/auth/keys\";\nconst LOGIN_TIMEOUT_MS = 5 * 60 * 1000;\nconst TOKEN_EXCHANGE_TIMEOUT_MS = 30_000;\n\ntype JsonObject = Record<string, unknown>;\n\ntype OpenRouterCallbackServer = {\n\tcallbackUrl: string;\n\tcredential: Promise<OAuthCredentials>;\n\tclose(): void;\n};\n\nfunction getCallbackHost(): string {\n\treturn process.env.PI_OAUTH_CALLBACK_HOST || \"127.0.0.1\";\n}\n\nfunction sendHtml(response: ServerResponse, status: number, html: string): void {\n\tresponse.statusCode = status;\n\tresponse.setHeader(\"content-type\", \"text/html; charset=utf-8\");\n\tresponse.setHeader(\"cache-control\", \"no-store\");\n\tresponse.end(html);\n}\n\nfunction errorDetail(body: JsonObject): string | undefined {\n\tif (typeof body.error_description === \"string\") return body.error_description;\n\tif (typeof body.message === \"string\") return body.message;\n\tif (typeof body.error === \"string\") return body.error;\n\tif (body.error && typeof body.error === \"object\" && !Array.isArray(body.error)) {\n\t\tconst message = (body.error as JsonObject).message;\n\t\tif (typeof message === \"string\") return message;\n\t}\n\treturn undefined;\n}\n\nasync function exchangeAuthorizationCode(\n\tcode: string,\n\tverifier: string,\n\tsignal?: AbortSignal,\n): Promise<OAuthCredentials> {\n\tif (signal?.aborted) throw new Error(\"Login cancelled\");\n\tconst controller = new AbortController();\n\tconst onAbort = () => controller.abort(signal?.reason);\n\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\tconst timeout = setTimeout(\n\t\t() => controller.abort(new Error(\"OpenRouter OAuth token exchange timed out\")),\n\t\tTOKEN_EXCHANGE_TIMEOUT_MS,\n\t);\n\n\tlet response: Response;\n\tlet body: JsonObject = {};\n\ttry {\n\t\tresponse = await fetch(TOKEN_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { accept: \"application/json\", \"content-type\": \"application/json\" },\n\t\t\tbody: JSON.stringify({ code, code_verifier: verifier, code_challenge_method: \"S256\" }),\n\t\t\tsignal: controller.signal,\n\t\t});\n\t\ttry {\n\t\t\tconst parsed = (await response.json()) as unknown;\n\t\t\tif (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) body = parsed as JsonObject;\n\t\t} catch {\n\t\t\tif (response.ok) throw new Error(\"OpenRouter OAuth returned invalid JSON\");\n\t\t}\n\t} catch (error) {\n\t\tif (signal?.aborted) throw new Error(\"Login cancelled\");\n\t\tif (controller.signal.aborted) throw new Error(\"OpenRouter OAuth token exchange timed out\");\n\t\tthrow error;\n\t} finally {\n\t\tclearTimeout(timeout);\n\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t}\n\n\tif (!response.ok) {\n\t\tconst detail = errorDetail(body);\n\t\tthrow new Error(`OpenRouter OAuth key exchange failed (HTTP ${response.status})${detail ? `: ${detail}` : \"\"}`);\n\t}\n\tif (typeof body.key !== \"string\" || body.key.length === 0) {\n\t\tthrow new Error('OpenRouter OAuth response carries no \"key\"');\n\t}\n\treturn { access: body.key, refresh: \"\", expires: Number.MAX_SAFE_INTEGER };\n}\n\nasync function startCallbackServer(\n\tcallbackPath: string,\n\tverifier: string,\n\tsignal?: AbortSignal,\n): Promise<OpenRouterCallbackServer> {\n\tif (signal?.aborted) throw new Error(\"Login cancelled\");\n\tconst callbackHost = getCallbackHost();\n\tlet resolveCredential: (credential: OAuthCredentials) => void = () => {};\n\tlet rejectCredential: (error: Error) => void = () => {};\n\tconst credential = new Promise<OAuthCredentials>((resolve, reject) => {\n\t\tresolveCredential = resolve;\n\t\trejectCredential = reject;\n\t});\n\n\tlet claimed = false;\n\tlet settled = false;\n\tlet timeout: ReturnType<typeof setTimeout> | undefined;\n\tlet onAbort: (() => void) | undefined;\n\tconst server = createServer((request, response) => {\n\t\tvoid (async () => {\n\t\t\tconst requestUrl = new URL(request.url ?? \"/\", `http://${callbackHost}`);\n\t\t\tif (request.method !== \"GET\" || requestUrl.pathname !== callbackPath) {\n\t\t\t\tsendHtml(response, 404, oauthErrorHtml(\"OAuth callback route not found.\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (claimed || settled) {\n\t\t\t\tsendHtml(response, 409, oauthErrorHtml(\"This OAuth callback has already been used.\"));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst oauthError = requestUrl.searchParams.get(\"error\");\n\t\t\tif (oauthError) {\n\t\t\t\tconst description = requestUrl.searchParams.get(\"error_description\") ?? oauthError;\n\t\t\t\tsendHtml(response, 400, oauthErrorHtml(\"OpenRouter authorization was denied.\", description));\n\t\t\t\tfinish({ error: new Error(`OpenRouter authorization failed: ${description}`) });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst code = requestUrl.searchParams.get(\"code\");\n\t\t\tif (!code) {\n\t\t\t\tsendHtml(response, 400, oauthErrorHtml(\"OpenRouter returned no authorization code.\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tclaimed = true;\n\n\t\t\ttry {\n\t\t\t\tconst result = await exchangeAuthorizationCode(code, verifier, signal);\n\t\t\t\tsendHtml(response, 200, oauthSuccessHtml(\"Signed in to OpenRouter. You may now close this page.\"));\n\t\t\t\tfinish({ credential: result });\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : \"Unknown token exchange error\";\n\t\t\t\tsendHtml(response, 502, oauthErrorHtml(\"OpenRouter key exchange failed.\", message));\n\t\t\t\tfinish({ error: error instanceof Error ? error : new Error(message) });\n\t\t\t}\n\t\t})();\n\t});\n\n\tconst finish = (result: { credential: OAuthCredentials } | { error: Error }): void => {\n\t\tif (settled) return;\n\t\tsettled = true;\n\t\tif (timeout) clearTimeout(timeout);\n\t\tif (onAbort) signal?.removeEventListener(\"abort\", onAbort);\n\t\tserver.close();\n\t\tif (\"credential\" in result) resolveCredential(result.credential);\n\t\telse rejectCredential(result.error);\n\t};\n\n\tawait new Promise<void>((resolve, reject) => {\n\t\tserver.once(\"error\", reject);\n\t\tserver.listen(0, callbackHost, () => {\n\t\t\tserver.removeListener(\"error\", reject);\n\t\t\tresolve();\n\t\t});\n\t});\n\n\tserver.on(\"error\", (error) => finish({ error }));\n\tonAbort = () => finish({ error: new Error(\"Login cancelled\") });\n\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\tif (signal?.aborted) {\n\t\tsignal.removeEventListener(\"abort\", onAbort);\n\t\tserver.close();\n\t\tthrow new Error(\"Login cancelled\");\n\t}\n\ttimeout = setTimeout(() => finish({ error: new Error(\"OpenRouter OAuth login timed out\") }), LOGIN_TIMEOUT_MS);\n\n\tconst address = server.address();\n\tif (!address || typeof address === \"string\") {\n\t\tfinish({ error: new Error(\"Could not determine the OpenRouter OAuth callback port\") });\n\t\tthrow new Error(\"Could not determine the OpenRouter OAuth callback port\");\n\t}\n\treturn {\n\t\tcallbackUrl: `http://${callbackHost}:${address.port}${callbackPath}`,\n\t\tcredential,\n\t\tclose: () => finish({ error: new Error(\"Login cancelled\") }),\n\t};\n}\n\nexport async function loginOpenRouter(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\tconst { verifier, challenge } = await generatePKCE();\n\tconst callbackPath = `/oauth/callback/${randomUUID()}`;\n\tconst callback = await startCallbackServer(callbackPath, verifier, callbacks.signal);\n\tconst authorizeUrl = new URL(AUTHORIZE_URL);\n\tauthorizeUrl.search = new URLSearchParams({\n\t\tcallback_url: callback.callbackUrl,\n\t\tcode_challenge: challenge,\n\t\tcode_challenge_method: \"S256\",\n\t}).toString();\n\tcallbacks.onProgress?.(`Listening for OpenRouter OAuth callback on ${callback.callbackUrl}`);\n\tcallbacks.onAuth({ url: authorizeUrl.toString(), instructions: \"Complete sign-in in your browser.\" });\n\ttry {\n\t\treturn await callback.credential;\n\t} finally {\n\t\tcallback.close();\n\t}\n}\n\nexport const openRouterOAuthProvider: OAuthProviderInterface = {\n\tid: \"openrouter\",\n\tname: \"OpenRouter OAuth\",\n\tusesCallbackServer: true,\n\tlogin: loginOpenRouter,\n\trefreshToken: async (credentials) => credentials,\n\tgetApiKey: (credentials) => credentials.access,\n};\n"]}
@@ -0,0 +1,6 @@
1
+ /** xAI OAuth device-code flow. */
2
+ import type { OAuthCredentials, OAuthLoginCallbacks, OAuthProviderInterface } from "./types.ts";
3
+ export declare function loginXai(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials>;
4
+ export declare function refreshXaiToken(refreshToken: string): Promise<OAuthCredentials>;
5
+ export declare const xaiOAuthProvider: OAuthProviderInterface;
6
+ //# sourceMappingURL=xai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xai.d.ts","sourceRoot":"","sources":["../../../src/utils/oauth/xai.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAGlC,OAAO,KAAK,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AA2JhG,wBAAsB,QAAQ,CAAC,SAAS,EAAE,mBAAmB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CASxF;AAED,wBAAsB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAQrF;AAED,eAAO,MAAM,gBAAgB,EAAE,sBAM9B,CAAC","sourcesContent":["/** xAI OAuth device-code flow. */\n\nimport { pollOAuthDeviceCodeFlow } from \"./device-code.ts\";\nimport type { OAuthCredentials, OAuthLoginCallbacks, OAuthProviderInterface } from \"./types.ts\";\n\nconst XAI_CLIENT_ID = \"b1a00492-073a-47ea-816f-4c329264a828\";\nconst XAI_SCOPE = \"openid profile email offline_access grok-cli:access api:access\";\nconst XAI_DEVICE_CODE_URL = \"https://auth.x.ai/oauth2/device/code\";\nconst XAI_TOKEN_URL = \"https://auth.x.ai/oauth2/token\";\nconst REFRESH_SKEW_MS = 5 * 60 * 1000;\nconst DEFAULT_TOKEN_LIFETIME_SECONDS = 3600;\n\ntype JsonObject = Record<string, unknown>;\n\ntype OAuthHttpResponse = {\n\tok: boolean;\n\tstatus: number;\n\tbody: JsonObject;\n};\n\ntype XaiDeviceCode = {\n\tdeviceCode: string;\n\tuserCode: string;\n\tverificationUri: string;\n\tintervalSeconds?: number;\n\texpiresInSeconds: number;\n};\n\nfunction requiredString(body: JsonObject, field: string): string {\n\tconst value = body[field];\n\tif (typeof value !== \"string\" || value.length === 0) {\n\t\tthrow new Error(`Invalid xAI OAuth response field: ${field}`);\n\t}\n\treturn value;\n}\n\nfunction positiveNumber(body: JsonObject, field: string): number {\n\tconst value = body[field];\n\tif (typeof value !== \"number\" || !Number.isFinite(value) || value <= 0) {\n\t\tthrow new Error(`Invalid xAI OAuth response field: ${field}`);\n\t}\n\treturn value;\n}\n\nfunction validateVerificationUri(raw: string): string {\n\tlet url: URL;\n\ttry {\n\t\turl = new URL(raw);\n\t} catch {\n\t\tthrow new Error(\"Untrusted verification URI in xAI OAuth response\");\n\t}\n\tif (url.protocol !== \"https:\") {\n\t\tthrow new Error(\"Untrusted verification URI in xAI OAuth response\");\n\t}\n\treturn url.href;\n}\n\nasync function postForm(url: string, fields: Record<string, string>, signal?: AbortSignal): Promise<OAuthHttpResponse> {\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetch(url, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\tAccept: \"application/json\",\n\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t},\n\t\t\tbody: new URLSearchParams(fields),\n\t\t\tsignal,\n\t\t});\n\t} catch (error) {\n\t\tif (signal?.aborted) throw new Error(\"Login cancelled\");\n\t\tthrow error;\n\t}\n\n\tlet body: JsonObject;\n\ttry {\n\t\tconst parsed = (await response.json()) as unknown;\n\t\tbody = parsed && typeof parsed === \"object\" && !Array.isArray(parsed) ? (parsed as JsonObject) : {};\n\t} catch {\n\t\tif (signal?.aborted) throw new Error(\"Login cancelled\");\n\t\tthrow new Error(`xAI OAuth returned invalid JSON (HTTP ${response.status})`);\n\t}\n\treturn { ok: response.ok, status: response.status, body };\n}\n\nfunction requestFailure(action: string, response: OAuthHttpResponse): Error {\n\tconst error = typeof response.body.error === \"string\" ? response.body.error : undefined;\n\tconst description =\n\t\ttypeof response.body.error_description === \"string\" ? response.body.error_description : undefined;\n\tconst detail = [error, description].filter(Boolean).join(\": \");\n\treturn new Error(`xAI OAuth ${action} failed (HTTP ${response.status})${detail ? `: ${detail}` : \"\"}`);\n}\n\nfunction parseDeviceCode(body: JsonObject): XaiDeviceCode {\n\tconst interval = body.interval;\n\treturn {\n\t\tdeviceCode: requiredString(body, \"device_code\"),\n\t\tuserCode: requiredString(body, \"user_code\"),\n\t\tverificationUri: validateVerificationUri(requiredString(body, \"verification_uri\")),\n\t\tintervalSeconds: typeof interval === \"number\" && Number.isFinite(interval) && interval > 0 ? interval : undefined,\n\t\texpiresInSeconds: positiveNumber(body, \"expires_in\"),\n\t};\n}\n\nfunction credentialsFromTokenResponse(body: JsonObject, previousRefreshToken?: string): OAuthCredentials {\n\tconst access = requiredString(body, \"access_token\");\n\tconst refresh =\n\t\tbody.refresh_token === undefined && previousRefreshToken\n\t\t\t? previousRefreshToken\n\t\t\t: requiredString(body, \"refresh_token\");\n\tconst expiresInSeconds =\n\t\tbody.expires_in === undefined ? DEFAULT_TOKEN_LIFETIME_SECONDS : positiveNumber(body, \"expires_in\");\n\treturn {\n\t\taccess,\n\t\trefresh,\n\t\texpires: Date.now() + expiresInSeconds * 1000 - REFRESH_SKEW_MS,\n\t};\n}\n\nasync function requestDeviceCode(signal?: AbortSignal): Promise<XaiDeviceCode> {\n\tconst response = await postForm(\n\t\tXAI_DEVICE_CODE_URL,\n\t\t{ client_id: XAI_CLIENT_ID, scope: XAI_SCOPE, referrer: \"pi\" },\n\t\tsignal,\n\t);\n\tif (!response.ok) throw requestFailure(\"device authorization\", response);\n\treturn parseDeviceCode(response.body);\n}\n\nasync function pollForTokens(device: XaiDeviceCode, signal?: AbortSignal): Promise<OAuthCredentials> {\n\treturn pollOAuthDeviceCodeFlow<OAuthCredentials>({\n\t\tintervalSeconds: device.intervalSeconds,\n\t\texpiresInSeconds: device.expiresInSeconds,\n\t\tsignal,\n\t\tpoll: async () => {\n\t\t\tconst response = await postForm(\n\t\t\t\tXAI_TOKEN_URL,\n\t\t\t\t{\n\t\t\t\t\tgrant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n\t\t\t\t\tclient_id: XAI_CLIENT_ID,\n\t\t\t\t\tdevice_code: device.deviceCode,\n\t\t\t\t},\n\t\t\t\tsignal,\n\t\t\t);\n\t\t\tif (response.ok) return { status: \"complete\", value: credentialsFromTokenResponse(response.body) };\n\n\t\t\tconst error = response.body.error;\n\t\t\tif (error === \"authorization_pending\") return { status: \"pending\" };\n\t\t\tif (error === \"slow_down\") return { status: \"slow_down\" };\n\t\t\tif (error === \"access_denied\" || error === \"authorization_denied\") {\n\t\t\t\treturn { status: \"failed\", message: \"xAI device authorization was denied\" };\n\t\t\t}\n\t\t\tif (error === \"expired_token\") return { status: \"failed\", message: \"xAI device code expired\" };\n\t\t\treturn { status: \"failed\", message: requestFailure(\"device token polling\", response).message };\n\t\t},\n\t});\n}\n\nexport async function loginXai(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\tconst device = await requestDeviceCode(callbacks.signal);\n\tcallbacks.onDeviceCode({\n\t\tuserCode: device.userCode,\n\t\tverificationUri: device.verificationUri,\n\t\tintervalSeconds: device.intervalSeconds,\n\t\texpiresInSeconds: device.expiresInSeconds,\n\t});\n\treturn pollForTokens(device, callbacks.signal);\n}\n\nexport async function refreshXaiToken(refreshToken: string): Promise<OAuthCredentials> {\n\tconst response = await postForm(XAI_TOKEN_URL, {\n\t\tgrant_type: \"refresh_token\",\n\t\tclient_id: XAI_CLIENT_ID,\n\t\trefresh_token: refreshToken,\n\t});\n\tif (!response.ok) throw requestFailure(\"token refresh\", response);\n\treturn credentialsFromTokenResponse(response.body, refreshToken);\n}\n\nexport const xaiOAuthProvider: OAuthProviderInterface = {\n\tid: \"xai\",\n\tname: \"xAI (Grok/X subscription)\",\n\tlogin: loginXai,\n\trefreshToken: (credentials) => refreshXaiToken(credentials.refresh),\n\tgetApiKey: (credentials) => credentials.access,\n};\n"]}
@@ -0,0 +1,154 @@
1
+ /** xAI OAuth device-code flow. */
2
+ import { pollOAuthDeviceCodeFlow } from "./device-code.js";
3
+ const XAI_CLIENT_ID = "b1a00492-073a-47ea-816f-4c329264a828";
4
+ const XAI_SCOPE = "openid profile email offline_access grok-cli:access api:access";
5
+ const XAI_DEVICE_CODE_URL = "https://auth.x.ai/oauth2/device/code";
6
+ const XAI_TOKEN_URL = "https://auth.x.ai/oauth2/token";
7
+ const REFRESH_SKEW_MS = 5 * 60 * 1000;
8
+ const DEFAULT_TOKEN_LIFETIME_SECONDS = 3600;
9
+ function requiredString(body, field) {
10
+ const value = body[field];
11
+ if (typeof value !== "string" || value.length === 0) {
12
+ throw new Error(`Invalid xAI OAuth response field: ${field}`);
13
+ }
14
+ return value;
15
+ }
16
+ function positiveNumber(body, field) {
17
+ const value = body[field];
18
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
19
+ throw new Error(`Invalid xAI OAuth response field: ${field}`);
20
+ }
21
+ return value;
22
+ }
23
+ function validateVerificationUri(raw) {
24
+ let url;
25
+ try {
26
+ url = new URL(raw);
27
+ }
28
+ catch {
29
+ throw new Error("Untrusted verification URI in xAI OAuth response");
30
+ }
31
+ if (url.protocol !== "https:") {
32
+ throw new Error("Untrusted verification URI in xAI OAuth response");
33
+ }
34
+ return url.href;
35
+ }
36
+ async function postForm(url, fields, signal) {
37
+ let response;
38
+ try {
39
+ response = await fetch(url, {
40
+ method: "POST",
41
+ headers: {
42
+ Accept: "application/json",
43
+ "Content-Type": "application/x-www-form-urlencoded",
44
+ },
45
+ body: new URLSearchParams(fields),
46
+ signal,
47
+ });
48
+ }
49
+ catch (error) {
50
+ if (signal?.aborted)
51
+ throw new Error("Login cancelled");
52
+ throw error;
53
+ }
54
+ let body;
55
+ try {
56
+ const parsed = (await response.json());
57
+ body = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
58
+ }
59
+ catch {
60
+ if (signal?.aborted)
61
+ throw new Error("Login cancelled");
62
+ throw new Error(`xAI OAuth returned invalid JSON (HTTP ${response.status})`);
63
+ }
64
+ return { ok: response.ok, status: response.status, body };
65
+ }
66
+ function requestFailure(action, response) {
67
+ const error = typeof response.body.error === "string" ? response.body.error : undefined;
68
+ const description = typeof response.body.error_description === "string" ? response.body.error_description : undefined;
69
+ const detail = [error, description].filter(Boolean).join(": ");
70
+ return new Error(`xAI OAuth ${action} failed (HTTP ${response.status})${detail ? `: ${detail}` : ""}`);
71
+ }
72
+ function parseDeviceCode(body) {
73
+ const interval = body.interval;
74
+ return {
75
+ deviceCode: requiredString(body, "device_code"),
76
+ userCode: requiredString(body, "user_code"),
77
+ verificationUri: validateVerificationUri(requiredString(body, "verification_uri")),
78
+ intervalSeconds: typeof interval === "number" && Number.isFinite(interval) && interval > 0 ? interval : undefined,
79
+ expiresInSeconds: positiveNumber(body, "expires_in"),
80
+ };
81
+ }
82
+ function credentialsFromTokenResponse(body, previousRefreshToken) {
83
+ const access = requiredString(body, "access_token");
84
+ const refresh = body.refresh_token === undefined && previousRefreshToken
85
+ ? previousRefreshToken
86
+ : requiredString(body, "refresh_token");
87
+ const expiresInSeconds = body.expires_in === undefined ? DEFAULT_TOKEN_LIFETIME_SECONDS : positiveNumber(body, "expires_in");
88
+ return {
89
+ access,
90
+ refresh,
91
+ expires: Date.now() + expiresInSeconds * 1000 - REFRESH_SKEW_MS,
92
+ };
93
+ }
94
+ async function requestDeviceCode(signal) {
95
+ const response = await postForm(XAI_DEVICE_CODE_URL, { client_id: XAI_CLIENT_ID, scope: XAI_SCOPE, referrer: "pi" }, signal);
96
+ if (!response.ok)
97
+ throw requestFailure("device authorization", response);
98
+ return parseDeviceCode(response.body);
99
+ }
100
+ async function pollForTokens(device, signal) {
101
+ return pollOAuthDeviceCodeFlow({
102
+ intervalSeconds: device.intervalSeconds,
103
+ expiresInSeconds: device.expiresInSeconds,
104
+ signal,
105
+ poll: async () => {
106
+ const response = await postForm(XAI_TOKEN_URL, {
107
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code",
108
+ client_id: XAI_CLIENT_ID,
109
+ device_code: device.deviceCode,
110
+ }, signal);
111
+ if (response.ok)
112
+ return { status: "complete", value: credentialsFromTokenResponse(response.body) };
113
+ const error = response.body.error;
114
+ if (error === "authorization_pending")
115
+ return { status: "pending" };
116
+ if (error === "slow_down")
117
+ return { status: "slow_down" };
118
+ if (error === "access_denied" || error === "authorization_denied") {
119
+ return { status: "failed", message: "xAI device authorization was denied" };
120
+ }
121
+ if (error === "expired_token")
122
+ return { status: "failed", message: "xAI device code expired" };
123
+ return { status: "failed", message: requestFailure("device token polling", response).message };
124
+ },
125
+ });
126
+ }
127
+ export async function loginXai(callbacks) {
128
+ const device = await requestDeviceCode(callbacks.signal);
129
+ callbacks.onDeviceCode({
130
+ userCode: device.userCode,
131
+ verificationUri: device.verificationUri,
132
+ intervalSeconds: device.intervalSeconds,
133
+ expiresInSeconds: device.expiresInSeconds,
134
+ });
135
+ return pollForTokens(device, callbacks.signal);
136
+ }
137
+ export async function refreshXaiToken(refreshToken) {
138
+ const response = await postForm(XAI_TOKEN_URL, {
139
+ grant_type: "refresh_token",
140
+ client_id: XAI_CLIENT_ID,
141
+ refresh_token: refreshToken,
142
+ });
143
+ if (!response.ok)
144
+ throw requestFailure("token refresh", response);
145
+ return credentialsFromTokenResponse(response.body, refreshToken);
146
+ }
147
+ export const xaiOAuthProvider = {
148
+ id: "xai",
149
+ name: "xAI (Grok/X subscription)",
150
+ login: loginXai,
151
+ refreshToken: (credentials) => refreshXaiToken(credentials.refresh),
152
+ getApiKey: (credentials) => credentials.access,
153
+ };
154
+ //# sourceMappingURL=xai.js.map