omk-ai 0.96.2 → 0.98.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/cli.d.ts.map +1 -1
  2. package/dist/cli.js +2 -1
  3. package/dist/cli.js.map +1 -1
  4. package/dist/env-api-keys.d.ts.map +1 -1
  5. package/dist/env-api-keys.js +4 -6
  6. package/dist/env-api-keys.js.map +1 -1
  7. package/dist/image-models.generated.d.ts +75 -0
  8. package/dist/image-models.generated.d.ts.map +1 -1
  9. package/dist/image-models.generated.js +75 -0
  10. package/dist/image-models.generated.js.map +1 -1
  11. package/dist/models.d.ts.map +1 -1
  12. package/dist/models.generated.d.ts +3044 -4094
  13. package/dist/models.generated.d.ts.map +1 -1
  14. package/dist/models.generated.js +1121 -2137
  15. package/dist/models.generated.js.map +1 -1
  16. package/dist/models.js +4 -1
  17. package/dist/models.js.map +1 -1
  18. package/dist/providers/amazon-bedrock.d.ts.map +1 -1
  19. package/dist/providers/amazon-bedrock.js +1 -1
  20. package/dist/providers/amazon-bedrock.js.map +1 -1
  21. package/dist/providers/cloudflare.d.ts.map +1 -1
  22. package/dist/providers/cloudflare.js +1 -2
  23. package/dist/providers/cloudflare.js.map +1 -1
  24. package/dist/stream.d.ts +2 -0
  25. package/dist/stream.d.ts.map +1 -1
  26. package/dist/stream.js +24 -0
  27. package/dist/stream.js.map +1 -1
  28. package/dist/utils/oauth/google-oauth-shared.d.ts.map +1 -1
  29. package/dist/utils/oauth/google-oauth-shared.js.map +1 -1
  30. package/dist/utils/oauth/qwen.d.ts +1 -1
  31. package/dist/utils/oauth/qwen.d.ts.map +1 -1
  32. package/dist/utils/oauth/qwen.js +50 -19
  33. package/dist/utils/oauth/qwen.js.map +1 -1
  34. package/dist/utils/oauth/xai.d.ts.map +1 -1
  35. package/dist/utils/oauth/xai.js +1 -1
  36. package/dist/utils/oauth/xai.js.map +1 -1
  37. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"xai.d.ts","sourceRoot":"","sources":["../../../src/utils/oauth/xai.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAehG,eAAO,MAAM,qBAAqB,QAAQ,CAAC;AAoC3C,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,SAAI,GAAG,OAAO,CAiB9E;AA6MD,uEAAuE;AACvE,wBAAsB,QAAQ,CAAC,SAAS,EAAE,mBAAmB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAgBxF;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA2CrF;AAED,eAAO,MAAM,gBAAgB,EAAE,sBAa9B,CAAC","sourcesContent":["/**\n * xAI Grok OAuth (native device authorization flow).\n *\n * RFC 8628 device-authorization grant with OIDC discovery.\n * Uses the official xAI OAuth client id and scopes.\n */\nimport { applyGrokThinking } from \"../../providers/grok-thinking.ts\";\nimport { pollOAuthDeviceCodeFlow } from \"./device-code.ts\";\nimport type { OAuthCredentials, OAuthLoginCallbacks, OAuthProviderInterface } from \"./types.ts\";\n\nconst XAI_OAUTH_ISSUER = \"https://auth.x.ai\";\nconst XAI_OAUTH_DISCOVERY_URL = `${XAI_OAUTH_ISSUER}/.well-known/openid-configuration`;\nconst XAI_OAUTH_DEVICE_CODE_URL = `${XAI_OAUTH_ISSUER}/oauth2/device/code`;\nconst XAI_OAUTH_CLIENT_ID = \"b1a00492-073a-47ea-816f-4c329264a828\";\nconst XAI_OAUTH_SCOPE =\n\t\"openid profile email offline_access grok-cli:access api:access conversations:read conversations:write workspaces:read workspaces:write\";\nconst XAI_OAUTH_REFERRER = \"grok-build\";\nconst XAI_OAUTH_CLIENT_SURFACE = \"ui\";\n\nconst ACCESS_TOKEN_CLIENT_SKEW_MS = 5 * 60 * 1000;\nconst DISCOVERY_TIMEOUT_MS = 15_000;\nconst TOKEN_REQUEST_TIMEOUT_MS = 20_000;\n\nexport const XAI_OAUTH_PROVIDER_ID = \"xai\";\nconst XAI_OAUTH_API_BASE_URL = \"https://api.x.ai/v1\";\n\ninterface XAIOAuthDiscovery {\n\ttoken_endpoint: string;\n}\n\ninterface XAIDeviceAuthorization {\n\tdeviceCode: string;\n\tuserCode: string;\n\tverificationUriComplete: string;\n\texpiresInSeconds: number;\n\tintervalSeconds: number;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null;\n}\n\nfunction validateXAIEndpoint(url: string, field: string): string {\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(url);\n\t} catch {\n\t\tthrow new Error(`Invalid xAI ${field}: ${url}`);\n\t}\n\tif (parsed.protocol !== \"https:\") {\n\t\tthrow new Error(`Invalid xAI ${field}: ${url}`);\n\t}\n\tconst host = parsed.hostname.toLowerCase();\n\tif (!host || (host !== \"x.ai\" && !host.endsWith(\".x.ai\"))) {\n\t\tthrow new Error(`Invalid xAI ${field}: ${url}`);\n\t}\n\treturn url;\n}\n\nexport function isXAIAccessTokenExpiring(jwt: string, skewSeconds = 0): boolean {\n\ttry {\n\t\tif (typeof jwt !== \"string\" || !jwt.includes(\".\")) return false;\n\t\tconst parts = jwt.split(\".\");\n\t\tif (parts.length < 2) return false;\n\t\tconst payloadPart = parts[1];\n\t\tif (!payloadPart) return false;\n\t\tconst decoded = Buffer.from(payloadPart, \"base64url\").toString(\"utf8\");\n\t\tconst payload: unknown = JSON.parse(decoded);\n\t\tif (!isRecord(payload)) return false;\n\t\tconst exp = payload.exp;\n\t\tif (typeof exp !== \"number\" || !Number.isFinite(exp)) return false;\n\t\tconst now = Math.floor(Date.now() / 1000);\n\t\treturn exp <= now + Math.max(0, Math.floor(skewSeconds));\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nasync function xaiOAuthDiscovery(timeoutMs = DISCOVERY_TIMEOUT_MS): Promise<XAIOAuthDiscovery> {\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetch(XAI_OAUTH_DISCOVERY_URL, {\n\t\t\tmethod: \"GET\",\n\t\t\theaders: { Accept: \"application/json\" },\n\t\t\tsignal: AbortSignal.timeout(timeoutMs),\n\t\t});\n\t} catch (error) {\n\t\tthrow new Error(`xAI OIDC discovery failed: ${error instanceof Error ? error.message : String(error)}`);\n\t}\n\tif (response.status !== 200) {\n\t\tthrow new Error(`xAI OIDC discovery returned status ${response.status}.`);\n\t}\n\tlet payload: unknown;\n\ttry {\n\t\tpayload = await response.json();\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`xAI OIDC discovery returned invalid JSON: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n\tif (!isRecord(payload)) {\n\t\tthrow new Error(\"xAI OIDC discovery response was not a JSON object.\");\n\t}\n\tconst tokenEndpoint = typeof payload.token_endpoint === \"string\" ? payload.token_endpoint.trim() : \"\";\n\tif (!tokenEndpoint) {\n\t\tthrow new Error(\"xAI OIDC discovery response was missing token_endpoint.\");\n\t}\n\tvalidateXAIEndpoint(tokenEndpoint, \"token_endpoint\");\n\treturn { token_endpoint: tokenEndpoint };\n}\n\nfunction parseXAIDeviceAuthorization(payload: unknown): XAIDeviceAuthorization {\n\tif (!isRecord(payload)) {\n\t\tthrow new Error(\"xAI device-code response was not a JSON object.\");\n\t}\n\n\tconst deviceCode = typeof payload.device_code === \"string\" ? payload.device_code.trim() : \"\";\n\tconst userCode = typeof payload.user_code === \"string\" ? payload.user_code.trim() : \"\";\n\tconst verificationUri = typeof payload.verification_uri === \"string\" ? payload.verification_uri.trim() : \"\";\n\tconst verificationUriComplete =\n\t\ttypeof payload.verification_uri_complete === \"string\" ? payload.verification_uri_complete.trim() : \"\";\n\tconst expiresInSeconds = payload.expires_in;\n\tconst intervalSeconds = payload.interval;\n\tif (\n\t\t!deviceCode ||\n\t\t!userCode ||\n\t\t!verificationUri ||\n\t\t!verificationUriComplete ||\n\t\ttypeof expiresInSeconds !== \"number\" ||\n\t\t!Number.isFinite(expiresInSeconds) ||\n\t\texpiresInSeconds <= 0 ||\n\t\ttypeof intervalSeconds !== \"number\" ||\n\t\t!Number.isFinite(intervalSeconds) ||\n\t\tintervalSeconds <= 0\n\t) {\n\t\tthrow new Error(\"xAI device-code response missing or invalid required fields.\");\n\t}\n\n\tvalidateXAIEndpoint(verificationUri, \"verification_uri\");\n\tvalidateXAIEndpoint(verificationUriComplete, \"verification_uri_complete\");\n\treturn {\n\t\tdeviceCode,\n\t\tuserCode,\n\t\tverificationUriComplete,\n\t\texpiresInSeconds,\n\t\tintervalSeconds,\n\t};\n}\n\nfunction parseXAITokenResponse(payload: unknown, label: string, refreshTokenFallback?: string): OAuthCredentials {\n\tif (!isRecord(payload)) {\n\t\tthrow new Error(`${label} was not a JSON object`);\n\t}\n\tconst accessToken = typeof payload.access_token === \"string\" ? payload.access_token : \"\";\n\tconst responseRefreshToken = typeof payload.refresh_token === \"string\" ? payload.refresh_token : \"\";\n\tconst refreshToken = responseRefreshToken || refreshTokenFallback || \"\";\n\tconst expiresInSeconds = payload.expires_in;\n\tif (!accessToken) {\n\t\tthrow new Error(`${label} missing access_token`);\n\t}\n\tif (!refreshToken) {\n\t\tthrow new Error(`${label} missing refresh_token`);\n\t}\n\tif (typeof expiresInSeconds !== \"number\" || !Number.isFinite(expiresInSeconds)) {\n\t\tthrow new Error(`${label} missing expires_in`);\n\t}\n\treturn {\n\t\taccess: accessToken,\n\t\trefresh: refreshToken,\n\t\texpires: Date.now() + expiresInSeconds * 1000 - ACCESS_TOKEN_CLIENT_SKEW_MS,\n\t};\n}\n\nasync function requestXAIDeviceAuthorization(signal?: AbortSignal): Promise<XAIDeviceAuthorization> {\n\tlet response: Response;\n\ttry {\n\t\tconst timeoutSignal = AbortSignal.timeout(TOKEN_REQUEST_TIMEOUT_MS);\n\t\tresponse = await fetch(XAI_OAUTH_DEVICE_CODE_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\tAccept: \"application/json\",\n\t\t\t\t\"x-grok-client-surface\": XAI_OAUTH_CLIENT_SURFACE,\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tclient_id: XAI_OAUTH_CLIENT_ID,\n\t\t\t\tscope: XAI_OAUTH_SCOPE,\n\t\t\t\treferrer: XAI_OAUTH_REFERRER,\n\t\t\t}),\n\t\t\tsignal: signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal,\n\t\t});\n\t} catch (error) {\n\t\tif (signal?.aborted) throw new Error(\"Login cancelled\");\n\t\tthrow new Error(`xAI device-code request failed: ${error instanceof Error ? error.message : String(error)}`);\n\t}\n\n\tif (!response.ok) {\n\t\tlet detail = \"\";\n\t\ttry {\n\t\t\tdetail = (await response.text()).trim();\n\t\t} catch {\n\t\t\t// Ignore body-read failures\n\t\t}\n\t\tthrow new Error(`xAI device-code request failed: ${response.status}${detail ? ` ${detail}` : \"\"}`);\n\t}\n\n\tlet payload: unknown;\n\ttry {\n\t\tpayload = await response.json();\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`xAI device-code response returned invalid JSON: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n\treturn parseXAIDeviceAuthorization(payload);\n}\n\nasync function pollXAIDeviceToken(\n\ttokenEndpoint: string,\n\tdeviceCode: string,\n\tsignal?: AbortSignal,\n): Promise<\n\t| { status: \"pending\" }\n\t| { status: \"slow_down\" }\n\t| { status: \"failed\"; message: string }\n\t| { status: \"complete\"; value: OAuthCredentials }\n> {\n\tlet response: Response;\n\ttry {\n\t\tconst timeoutSignal = AbortSignal.timeout(TOKEN_REQUEST_TIMEOUT_MS);\n\t\tresponse = await fetch(tokenEndpoint, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\tAccept: \"application/json\",\n\t\t\t\t\"x-grok-client-surface\": XAI_OAUTH_CLIENT_SURFACE,\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tgrant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n\t\t\t\tclient_id: XAI_OAUTH_CLIENT_ID,\n\t\t\t\tdevice_code: deviceCode,\n\t\t\t}),\n\t\t\tsignal: signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal,\n\t\t});\n\t} catch (error) {\n\t\tif (signal?.aborted) throw new Error(\"Login cancelled\");\n\t\tthrow new Error(\n\t\t\t`xAI device-code token polling failed: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n\n\tlet payload: unknown;\n\ttry {\n\t\tpayload = await response.json();\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`xAI device-code token polling returned invalid JSON: ${\n\t\t\t\terror instanceof Error ? error.message : String(error)\n\t\t\t}`,\n\t\t);\n\t}\n\n\tif (response.ok) {\n\t\treturn {\n\t\t\tstatus: \"complete\",\n\t\t\tvalue: parseXAITokenResponse(payload, \"xAI device-code token response\"),\n\t\t};\n\t}\n\tif (!isRecord(payload)) {\n\t\tthrow new Error(`xAI device-code token polling failed: ${response.status}`);\n\t}\n\n\tconst errorCode = typeof payload.error === \"string\" ? payload.error : \"\";\n\tif (errorCode === \"authorization_pending\") return { status: \"pending\" };\n\tif (errorCode === \"slow_down\") return { status: \"slow_down\" };\n\n\tconst errorDescription = typeof payload.error_description === \"string\" ? payload.error_description : \"\";\n\tconst detail = errorDescription || errorCode || String(response.status);\n\tthrow new Error(`xAI device-code token polling failed: ${detail}`);\n}\n\n/** Log in to xAI Grok with the RFC 8628 device authorization grant. */\nexport async function loginXAI(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\tconst discovery = await xaiOAuthDiscovery(DISCOVERY_TIMEOUT_MS);\n\tconst device = await requestXAIDeviceAuthorization(callbacks.signal);\n\n\tcallbacks.onAuth({\n\t\turl: device.verificationUriComplete,\n\t\tinstructions: `Enter code: ${device.userCode}`,\n\t});\n\tcallbacks.onProgress?.(\"Waiting for xAI device authorization...\");\n\n\treturn pollOAuthDeviceCodeFlow({\n\t\tpoll: () => pollXAIDeviceToken(discovery.token_endpoint, device.deviceCode, callbacks.signal),\n\t\tintervalSeconds: device.intervalSeconds,\n\t\texpiresInSeconds: device.expiresInSeconds,\n\t\tsignal: callbacks.signal,\n\t});\n}\n\n/**\n * Refresh an xAI OAuth access token using a stored refresh_token.\n * Re-runs OIDC discovery and re-validates the token endpoint before sending.\n */\nexport async function refreshXAIToken(refreshToken: string): Promise<OAuthCredentials> {\n\tif (typeof refreshToken !== \"string\" || !refreshToken.trim()) {\n\t\tthrow new Error(\"missing refresh_token\");\n\t}\n\n\tconst discovery = await xaiOAuthDiscovery(DISCOVERY_TIMEOUT_MS);\n\tconst tokenEndpoint = validateXAIEndpoint(discovery.token_endpoint, \"token_endpoint\");\n\n\tconst body = new URLSearchParams({\n\t\tgrant_type: \"refresh_token\",\n\t\tclient_id: XAI_OAUTH_CLIENT_ID,\n\t\trefresh_token: refreshToken,\n\t});\n\n\tconst response = await fetch(tokenEndpoint, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\tAccept: \"application/json\",\n\t\t},\n\t\tbody,\n\t\tsignal: AbortSignal.timeout(TOKEN_REQUEST_TIMEOUT_MS),\n\t});\n\n\tif (!response.ok) {\n\t\tlet detail = \"\";\n\t\ttry {\n\t\t\tdetail = (await response.text()).trim();\n\t\t} catch {\n\t\t\t// Ignore body-read failures\n\t\t}\n\t\tthrow new Error(`xAI token refresh failed: ${response.status}${detail ? ` ${detail}` : \"\"}`);\n\t}\n\n\tlet payload: unknown;\n\ttry {\n\t\tpayload = await response.json();\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`xAI token refresh returned invalid JSON: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n\treturn parseXAITokenResponse(payload, \"xAI token refresh response\", refreshToken);\n}\n\nexport const xaiOAuthProvider: OAuthProviderInterface = {\n\tid: XAI_OAUTH_PROVIDER_ID,\n\tname: \"xAI Grok (SuperGrok or X Premium+)\",\n\tlogin: loginXAI,\n\trefreshToken: (credentials: OAuthCredentials) => refreshXAIToken(credentials.refresh),\n\tgetApiKey: (credentials: OAuthCredentials) => credentials.access,\n\tmodifyModels(models) {\n\t\treturn models.map((model) =>\n\t\t\tmodel.provider === XAI_OAUTH_PROVIDER_ID\n\t\t\t\t? applyGrokThinking({ ...model, baseUrl: XAI_OAUTH_API_BASE_URL })\n\t\t\t\t: model,\n\t\t);\n\t},\n};\n"]}
1
+ {"version":3,"file":"xai.d.ts","sourceRoot":"","sources":["../../../src/utils/oauth/xai.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAehG,eAAO,MAAM,qBAAqB,QAAQ,CAAC;AAoC3C,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,SAAI,GAAG,OAAO,CAiB9E;AA6MD,uEAAuE;AACvE,wBAAsB,QAAQ,CAAC,SAAS,EAAE,mBAAmB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAgBxF;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA2CrF;AAED,eAAO,MAAM,gBAAgB,EAAE,sBAa9B,CAAC","sourcesContent":["/**\n * xAI Grok OAuth (native device authorization flow).\n *\n * RFC 8628 device-authorization grant with OIDC discovery.\n * Uses the official xAI OAuth client id and scopes.\n */\nimport { applyGrokThinking } from \"../../providers/grok-thinking.ts\";\nimport { pollOAuthDeviceCodeFlow } from \"./device-code.ts\";\nimport type { OAuthCredentials, OAuthLoginCallbacks, OAuthProviderInterface } from \"./types.ts\";\n\nconst XAI_OAUTH_ISSUER = \"https://auth.x.ai\";\nconst XAI_OAUTH_DISCOVERY_URL = `${XAI_OAUTH_ISSUER}/.well-known/openid-configuration`;\nconst XAI_OAUTH_DEVICE_CODE_URL = `${XAI_OAUTH_ISSUER}/oauth2/device/code`;\nconst XAI_OAUTH_CLIENT_ID = \"b1a00492-073a-47ea-816f-4c329264a828\"; // gitleaks:allow -- public native-app OAuth client id\nconst XAI_OAUTH_SCOPE =\n\t\"openid profile email offline_access grok-cli:access api:access conversations:read conversations:write workspaces:read workspaces:write\";\nconst XAI_OAUTH_REFERRER = \"grok-build\";\nconst XAI_OAUTH_CLIENT_SURFACE = \"ui\";\n\nconst ACCESS_TOKEN_CLIENT_SKEW_MS = 5 * 60 * 1000;\nconst DISCOVERY_TIMEOUT_MS = 15_000;\nconst TOKEN_REQUEST_TIMEOUT_MS = 20_000;\n\nexport const XAI_OAUTH_PROVIDER_ID = \"xai\";\nconst XAI_OAUTH_API_BASE_URL = \"https://api.x.ai/v1\";\n\ninterface XAIOAuthDiscovery {\n\ttoken_endpoint: string;\n}\n\ninterface XAIDeviceAuthorization {\n\tdeviceCode: string;\n\tuserCode: string;\n\tverificationUriComplete: string;\n\texpiresInSeconds: number;\n\tintervalSeconds: number;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null;\n}\n\nfunction validateXAIEndpoint(url: string, field: string): string {\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(url);\n\t} catch {\n\t\tthrow new Error(`Invalid xAI ${field}: ${url}`);\n\t}\n\tif (parsed.protocol !== \"https:\") {\n\t\tthrow new Error(`Invalid xAI ${field}: ${url}`);\n\t}\n\tconst host = parsed.hostname.toLowerCase();\n\tif (!host || (host !== \"x.ai\" && !host.endsWith(\".x.ai\"))) {\n\t\tthrow new Error(`Invalid xAI ${field}: ${url}`);\n\t}\n\treturn url;\n}\n\nexport function isXAIAccessTokenExpiring(jwt: string, skewSeconds = 0): boolean {\n\ttry {\n\t\tif (typeof jwt !== \"string\" || !jwt.includes(\".\")) return false;\n\t\tconst parts = jwt.split(\".\");\n\t\tif (parts.length < 2) return false;\n\t\tconst payloadPart = parts[1];\n\t\tif (!payloadPart) return false;\n\t\tconst decoded = Buffer.from(payloadPart, \"base64url\").toString(\"utf8\");\n\t\tconst payload: unknown = JSON.parse(decoded);\n\t\tif (!isRecord(payload)) return false;\n\t\tconst exp = payload.exp;\n\t\tif (typeof exp !== \"number\" || !Number.isFinite(exp)) return false;\n\t\tconst now = Math.floor(Date.now() / 1000);\n\t\treturn exp <= now + Math.max(0, Math.floor(skewSeconds));\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nasync function xaiOAuthDiscovery(timeoutMs = DISCOVERY_TIMEOUT_MS): Promise<XAIOAuthDiscovery> {\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetch(XAI_OAUTH_DISCOVERY_URL, {\n\t\t\tmethod: \"GET\",\n\t\t\theaders: { Accept: \"application/json\" },\n\t\t\tsignal: AbortSignal.timeout(timeoutMs),\n\t\t});\n\t} catch (error) {\n\t\tthrow new Error(`xAI OIDC discovery failed: ${error instanceof Error ? error.message : String(error)}`);\n\t}\n\tif (response.status !== 200) {\n\t\tthrow new Error(`xAI OIDC discovery returned status ${response.status}.`);\n\t}\n\tlet payload: unknown;\n\ttry {\n\t\tpayload = await response.json();\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`xAI OIDC discovery returned invalid JSON: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n\tif (!isRecord(payload)) {\n\t\tthrow new Error(\"xAI OIDC discovery response was not a JSON object.\");\n\t}\n\tconst tokenEndpoint = typeof payload.token_endpoint === \"string\" ? payload.token_endpoint.trim() : \"\";\n\tif (!tokenEndpoint) {\n\t\tthrow new Error(\"xAI OIDC discovery response was missing token_endpoint.\");\n\t}\n\tvalidateXAIEndpoint(tokenEndpoint, \"token_endpoint\");\n\treturn { token_endpoint: tokenEndpoint };\n}\n\nfunction parseXAIDeviceAuthorization(payload: unknown): XAIDeviceAuthorization {\n\tif (!isRecord(payload)) {\n\t\tthrow new Error(\"xAI device-code response was not a JSON object.\");\n\t}\n\n\tconst deviceCode = typeof payload.device_code === \"string\" ? payload.device_code.trim() : \"\";\n\tconst userCode = typeof payload.user_code === \"string\" ? payload.user_code.trim() : \"\";\n\tconst verificationUri = typeof payload.verification_uri === \"string\" ? payload.verification_uri.trim() : \"\";\n\tconst verificationUriComplete =\n\t\ttypeof payload.verification_uri_complete === \"string\" ? payload.verification_uri_complete.trim() : \"\";\n\tconst expiresInSeconds = payload.expires_in;\n\tconst intervalSeconds = payload.interval;\n\tif (\n\t\t!deviceCode ||\n\t\t!userCode ||\n\t\t!verificationUri ||\n\t\t!verificationUriComplete ||\n\t\ttypeof expiresInSeconds !== \"number\" ||\n\t\t!Number.isFinite(expiresInSeconds) ||\n\t\texpiresInSeconds <= 0 ||\n\t\ttypeof intervalSeconds !== \"number\" ||\n\t\t!Number.isFinite(intervalSeconds) ||\n\t\tintervalSeconds <= 0\n\t) {\n\t\tthrow new Error(\"xAI device-code response missing or invalid required fields.\");\n\t}\n\n\tvalidateXAIEndpoint(verificationUri, \"verification_uri\");\n\tvalidateXAIEndpoint(verificationUriComplete, \"verification_uri_complete\");\n\treturn {\n\t\tdeviceCode,\n\t\tuserCode,\n\t\tverificationUriComplete,\n\t\texpiresInSeconds,\n\t\tintervalSeconds,\n\t};\n}\n\nfunction parseXAITokenResponse(payload: unknown, label: string, refreshTokenFallback?: string): OAuthCredentials {\n\tif (!isRecord(payload)) {\n\t\tthrow new Error(`${label} was not a JSON object`);\n\t}\n\tconst accessToken = typeof payload.access_token === \"string\" ? payload.access_token : \"\";\n\tconst responseRefreshToken = typeof payload.refresh_token === \"string\" ? payload.refresh_token : \"\";\n\tconst refreshToken = responseRefreshToken || refreshTokenFallback || \"\";\n\tconst expiresInSeconds = payload.expires_in;\n\tif (!accessToken) {\n\t\tthrow new Error(`${label} missing access_token`);\n\t}\n\tif (!refreshToken) {\n\t\tthrow new Error(`${label} missing refresh_token`);\n\t}\n\tif (typeof expiresInSeconds !== \"number\" || !Number.isFinite(expiresInSeconds)) {\n\t\tthrow new Error(`${label} missing expires_in`);\n\t}\n\treturn {\n\t\taccess: accessToken,\n\t\trefresh: refreshToken,\n\t\texpires: Date.now() + expiresInSeconds * 1000 - ACCESS_TOKEN_CLIENT_SKEW_MS,\n\t};\n}\n\nasync function requestXAIDeviceAuthorization(signal?: AbortSignal): Promise<XAIDeviceAuthorization> {\n\tlet response: Response;\n\ttry {\n\t\tconst timeoutSignal = AbortSignal.timeout(TOKEN_REQUEST_TIMEOUT_MS);\n\t\tresponse = await fetch(XAI_OAUTH_DEVICE_CODE_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\tAccept: \"application/json\",\n\t\t\t\t\"x-grok-client-surface\": XAI_OAUTH_CLIENT_SURFACE,\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tclient_id: XAI_OAUTH_CLIENT_ID,\n\t\t\t\tscope: XAI_OAUTH_SCOPE,\n\t\t\t\treferrer: XAI_OAUTH_REFERRER,\n\t\t\t}),\n\t\t\tsignal: signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal,\n\t\t});\n\t} catch (error) {\n\t\tif (signal?.aborted) throw new Error(\"Login cancelled\");\n\t\tthrow new Error(`xAI device-code request failed: ${error instanceof Error ? error.message : String(error)}`);\n\t}\n\n\tif (!response.ok) {\n\t\tlet detail = \"\";\n\t\ttry {\n\t\t\tdetail = (await response.text()).trim();\n\t\t} catch {\n\t\t\t// Ignore body-read failures\n\t\t}\n\t\tthrow new Error(`xAI device-code request failed: ${response.status}${detail ? ` ${detail}` : \"\"}`);\n\t}\n\n\tlet payload: unknown;\n\ttry {\n\t\tpayload = await response.json();\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`xAI device-code response returned invalid JSON: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n\treturn parseXAIDeviceAuthorization(payload);\n}\n\nasync function pollXAIDeviceToken(\n\ttokenEndpoint: string,\n\tdeviceCode: string,\n\tsignal?: AbortSignal,\n): Promise<\n\t| { status: \"pending\" }\n\t| { status: \"slow_down\" }\n\t| { status: \"failed\"; message: string }\n\t| { status: \"complete\"; value: OAuthCredentials }\n> {\n\tlet response: Response;\n\ttry {\n\t\tconst timeoutSignal = AbortSignal.timeout(TOKEN_REQUEST_TIMEOUT_MS);\n\t\tresponse = await fetch(tokenEndpoint, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\tAccept: \"application/json\",\n\t\t\t\t\"x-grok-client-surface\": XAI_OAUTH_CLIENT_SURFACE,\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tgrant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n\t\t\t\tclient_id: XAI_OAUTH_CLIENT_ID,\n\t\t\t\tdevice_code: deviceCode,\n\t\t\t}),\n\t\t\tsignal: signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal,\n\t\t});\n\t} catch (error) {\n\t\tif (signal?.aborted) throw new Error(\"Login cancelled\");\n\t\tthrow new Error(\n\t\t\t`xAI device-code token polling failed: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n\n\tlet payload: unknown;\n\ttry {\n\t\tpayload = await response.json();\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`xAI device-code token polling returned invalid JSON: ${\n\t\t\t\terror instanceof Error ? error.message : String(error)\n\t\t\t}`,\n\t\t);\n\t}\n\n\tif (response.ok) {\n\t\treturn {\n\t\t\tstatus: \"complete\",\n\t\t\tvalue: parseXAITokenResponse(payload, \"xAI device-code token response\"),\n\t\t};\n\t}\n\tif (!isRecord(payload)) {\n\t\tthrow new Error(`xAI device-code token polling failed: ${response.status}`);\n\t}\n\n\tconst errorCode = typeof payload.error === \"string\" ? payload.error : \"\";\n\tif (errorCode === \"authorization_pending\") return { status: \"pending\" };\n\tif (errorCode === \"slow_down\") return { status: \"slow_down\" };\n\n\tconst errorDescription = typeof payload.error_description === \"string\" ? payload.error_description : \"\";\n\tconst detail = errorDescription || errorCode || String(response.status);\n\tthrow new Error(`xAI device-code token polling failed: ${detail}`);\n}\n\n/** Log in to xAI Grok with the RFC 8628 device authorization grant. */\nexport async function loginXAI(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\tconst discovery = await xaiOAuthDiscovery(DISCOVERY_TIMEOUT_MS);\n\tconst device = await requestXAIDeviceAuthorization(callbacks.signal);\n\n\tcallbacks.onAuth({\n\t\turl: device.verificationUriComplete,\n\t\tinstructions: `Enter code: ${device.userCode}`,\n\t});\n\tcallbacks.onProgress?.(\"Waiting for xAI device authorization...\");\n\n\treturn pollOAuthDeviceCodeFlow({\n\t\tpoll: () => pollXAIDeviceToken(discovery.token_endpoint, device.deviceCode, callbacks.signal),\n\t\tintervalSeconds: device.intervalSeconds,\n\t\texpiresInSeconds: device.expiresInSeconds,\n\t\tsignal: callbacks.signal,\n\t});\n}\n\n/**\n * Refresh an xAI OAuth access token using a stored refresh_token.\n * Re-runs OIDC discovery and re-validates the token endpoint before sending.\n */\nexport async function refreshXAIToken(refreshToken: string): Promise<OAuthCredentials> {\n\tif (typeof refreshToken !== \"string\" || !refreshToken.trim()) {\n\t\tthrow new Error(\"missing refresh_token\");\n\t}\n\n\tconst discovery = await xaiOAuthDiscovery(DISCOVERY_TIMEOUT_MS);\n\tconst tokenEndpoint = validateXAIEndpoint(discovery.token_endpoint, \"token_endpoint\");\n\n\tconst body = new URLSearchParams({\n\t\tgrant_type: \"refresh_token\",\n\t\tclient_id: XAI_OAUTH_CLIENT_ID,\n\t\trefresh_token: refreshToken,\n\t});\n\n\tconst response = await fetch(tokenEndpoint, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\tAccept: \"application/json\",\n\t\t},\n\t\tbody,\n\t\tsignal: AbortSignal.timeout(TOKEN_REQUEST_TIMEOUT_MS),\n\t});\n\n\tif (!response.ok) {\n\t\tlet detail = \"\";\n\t\ttry {\n\t\t\tdetail = (await response.text()).trim();\n\t\t} catch {\n\t\t\t// Ignore body-read failures\n\t\t}\n\t\tthrow new Error(`xAI token refresh failed: ${response.status}${detail ? ` ${detail}` : \"\"}`);\n\t}\n\n\tlet payload: unknown;\n\ttry {\n\t\tpayload = await response.json();\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`xAI token refresh returned invalid JSON: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n\treturn parseXAITokenResponse(payload, \"xAI token refresh response\", refreshToken);\n}\n\nexport const xaiOAuthProvider: OAuthProviderInterface = {\n\tid: XAI_OAUTH_PROVIDER_ID,\n\tname: \"xAI Grok (SuperGrok or X Premium+)\",\n\tlogin: loginXAI,\n\trefreshToken: (credentials: OAuthCredentials) => refreshXAIToken(credentials.refresh),\n\tgetApiKey: (credentials: OAuthCredentials) => credentials.access,\n\tmodifyModels(models) {\n\t\treturn models.map((model) =>\n\t\t\tmodel.provider === XAI_OAUTH_PROVIDER_ID\n\t\t\t\t? applyGrokThinking({ ...model, baseUrl: XAI_OAUTH_API_BASE_URL })\n\t\t\t\t: model,\n\t\t);\n\t},\n};\n"]}
@@ -9,7 +9,7 @@ import { pollOAuthDeviceCodeFlow } from "./device-code.js";
9
9
  const XAI_OAUTH_ISSUER = "https://auth.x.ai";
10
10
  const XAI_OAUTH_DISCOVERY_URL = `${XAI_OAUTH_ISSUER}/.well-known/openid-configuration`;
11
11
  const XAI_OAUTH_DEVICE_CODE_URL = `${XAI_OAUTH_ISSUER}/oauth2/device/code`;
12
- const XAI_OAUTH_CLIENT_ID = "b1a00492-073a-47ea-816f-4c329264a828";
12
+ const XAI_OAUTH_CLIENT_ID = "b1a00492-073a-47ea-816f-4c329264a828"; // gitleaks:allow -- public native-app OAuth client id
13
13
  const XAI_OAUTH_SCOPE = "openid profile email offline_access grok-cli:access api:access conversations:read conversations:write workspaces:read workspaces:write";
14
14
  const XAI_OAUTH_REFERRER = "grok-build";
15
15
  const XAI_OAUTH_CLIENT_SURFACE = "ui";
@@ -1 +1 @@
1
- {"version":3,"file":"xai.js","sourceRoot":"","sources":["../../../src/utils/oauth/xai.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAG3D,MAAM,gBAAgB,GAAG,mBAAmB,CAAC;AAC7C,MAAM,uBAAuB,GAAG,GAAG,gBAAgB,mCAAmC,CAAC;AACvF,MAAM,yBAAyB,GAAG,GAAG,gBAAgB,qBAAqB,CAAC;AAC3E,MAAM,mBAAmB,GAAG,sCAAsC,CAAC;AACnE,MAAM,eAAe,GACpB,wIAAwI,CAAC;AAC1I,MAAM,kBAAkB,GAAG,YAAY,CAAC;AACxC,MAAM,wBAAwB,GAAG,IAAI,CAAC;AAEtC,MAAM,2BAA2B,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AAClD,MAAM,oBAAoB,GAAG,MAAM,CAAC;AACpC,MAAM,wBAAwB,GAAG,MAAM,CAAC;AAExC,MAAM,CAAC,MAAM,qBAAqB,GAAG,KAAK,CAAC;AAC3C,MAAM,sBAAsB,GAAG,qBAAqB,CAAC;AAcrD,SAAS,QAAQ,CAAC,KAAc,EAAoC;IACnE,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC;AAAA,CACnD;AAED,SAAS,mBAAmB,CAAC,GAAW,EAAE,KAAa,EAAU;IAChE,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACJ,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,IAAI,KAAK,CAAC,eAAe,KAAK,KAAK,GAAG,EAAE,CAAC,CAAC;IACjD,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,eAAe,KAAK,KAAK,GAAG,EAAE,CAAC,CAAC;IACjD,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;IAC3C,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;QAC3D,MAAM,IAAI,KAAK,CAAC,eAAe,KAAK,KAAK,GAAG,EAAE,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,GAAG,CAAC;AAAA,CACX;AAED,MAAM,UAAU,wBAAwB,CAAC,GAAW,EAAE,WAAW,GAAG,CAAC,EAAW;IAC/E,IAAI,CAAC;QACJ,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;QAChE,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;QACnC,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAC7B,IAAI,CAAC,WAAW;YAAE,OAAO,KAAK,CAAC;QAC/B,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACvE,MAAM,OAAO,GAAY,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC7C,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;YAAE,OAAO,KAAK,CAAC;QACrC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;QACxB,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;QACnE,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QAC1C,OAAO,GAAG,IAAI,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;IAC1D,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,KAAK,CAAC;IACd,CAAC;AAAA,CACD;AAED,KAAK,UAAU,iBAAiB,CAAC,SAAS,GAAG,oBAAoB,EAA8B;IAC9F,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACJ,QAAQ,GAAG,MAAM,KAAK,CAAC,uBAAuB,EAAE;YAC/C,MAAM,EAAE,KAAK;YACb,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE;YACvC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC;SACtC,CAAC,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,8BAA8B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACzG,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,sCAAsC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;IAC3E,CAAC;IACD,IAAI,OAAgB,CAAC;IACrB,IAAI,CAAC;QACJ,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IACjC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CACd,6CAA6C,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACrG,CAAC;IACH,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACvE,CAAC;IACD,MAAM,aAAa,GAAG,OAAO,OAAO,CAAC,cAAc,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACtG,IAAI,CAAC,aAAa,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC5E,CAAC;IACD,mBAAmB,CAAC,aAAa,EAAE,gBAAgB,CAAC,CAAC;IACrD,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,CAAC;AAAA,CACzC;AAED,SAAS,2BAA2B,CAAC,OAAgB,EAA0B;IAC9E,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACpE,CAAC;IAED,MAAM,UAAU,GAAG,OAAO,OAAO,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7F,MAAM,QAAQ,GAAG,OAAO,OAAO,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACvF,MAAM,eAAe,GAAG,OAAO,OAAO,CAAC,gBAAgB,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5G,MAAM,uBAAuB,GAC5B,OAAO,OAAO,CAAC,yBAAyB,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,yBAAyB,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACvG,MAAM,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC;IAC5C,MAAM,eAAe,GAAG,OAAO,CAAC,QAAQ,CAAC;IACzC,IACC,CAAC,UAAU;QACX,CAAC,QAAQ;QACT,CAAC,eAAe;QAChB,CAAC,uBAAuB;QACxB,OAAO,gBAAgB,KAAK,QAAQ;QACpC,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC;QAClC,gBAAgB,IAAI,CAAC;QACrB,OAAO,eAAe,KAAK,QAAQ;QACnC,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC;QACjC,eAAe,IAAI,CAAC,EACnB,CAAC;QACF,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;IACjF,CAAC;IAED,mBAAmB,CAAC,eAAe,EAAE,kBAAkB,CAAC,CAAC;IACzD,mBAAmB,CAAC,uBAAuB,EAAE,2BAA2B,CAAC,CAAC;IAC1E,OAAO;QACN,UAAU;QACV,QAAQ;QACR,uBAAuB;QACvB,gBAAgB;QAChB,eAAe;KACf,CAAC;AAAA,CACF;AAED,SAAS,qBAAqB,CAAC,OAAgB,EAAE,KAAa,EAAE,oBAA6B,EAAoB;IAChH,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,wBAAwB,CAAC,CAAC;IACnD,CAAC;IACD,MAAM,WAAW,GAAG,OAAO,OAAO,CAAC,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;IACzF,MAAM,oBAAoB,GAAG,OAAO,OAAO,CAAC,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;IACpG,MAAM,YAAY,GAAG,oBAAoB,IAAI,oBAAoB,IAAI,EAAE,CAAC;IACxE,MAAM,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC;IAC5C,IAAI,CAAC,WAAW,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,uBAAuB,CAAC,CAAC;IAClD,CAAC;IACD,IAAI,CAAC,YAAY,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,wBAAwB,CAAC,CAAC;IACnD,CAAC;IACD,IAAI,OAAO,gBAAgB,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;QAChF,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,qBAAqB,CAAC,CAAC;IAChD,CAAC;IACD,OAAO;QACN,MAAM,EAAE,WAAW;QACnB,OAAO,EAAE,YAAY;QACrB,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,gBAAgB,GAAG,IAAI,GAAG,2BAA2B;KAC3E,CAAC;AAAA,CACF;AAED,KAAK,UAAU,6BAA6B,CAAC,MAAoB,EAAmC;IACnG,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACJ,MAAM,aAAa,GAAG,WAAW,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAC;QACpE,QAAQ,GAAG,MAAM,KAAK,CAAC,yBAAyB,EAAE;YACjD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACR,cAAc,EAAE,mCAAmC;gBACnD,MAAM,EAAE,kBAAkB;gBAC1B,uBAAuB,EAAE,wBAAwB;aACjD;YACD,IAAI,EAAE,IAAI,eAAe,CAAC;gBACzB,SAAS,EAAE,mBAAmB;gBAC9B,KAAK,EAAE,eAAe;gBACtB,QAAQ,EAAE,kBAAkB;aAC5B,CAAC;YACF,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa;SACzE,CAAC,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,IAAI,MAAM,EAAE,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;QACxD,MAAM,IAAI,KAAK,CAAC,mCAAmC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC9G,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QAClB,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,CAAC;YACJ,MAAM,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACzC,CAAC;QAAC,MAAM,CAAC;YACR,4BAA4B;QAC7B,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,mCAAmC,QAAQ,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACpG,CAAC;IAED,IAAI,OAAgB,CAAC;IACrB,IAAI,CAAC;QACJ,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IACjC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CACd,mDAAmD,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAC3G,CAAC;IACH,CAAC;IACD,OAAO,2BAA2B,CAAC,OAAO,CAAC,CAAC;AAAA,CAC5C;AAED,KAAK,UAAU,kBAAkB,CAChC,aAAqB,EACrB,UAAkB,EAClB,MAAoB,EAMnB;IACD,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACJ,MAAM,aAAa,GAAG,WAAW,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAC;QACpE,QAAQ,GAAG,MAAM,KAAK,CAAC,aAAa,EAAE;YACrC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACR,cAAc,EAAE,mCAAmC;gBACnD,MAAM,EAAE,kBAAkB;gBAC1B,uBAAuB,EAAE,wBAAwB;aACjD;YACD,IAAI,EAAE,IAAI,eAAe,CAAC;gBACzB,UAAU,EAAE,8CAA8C;gBAC1D,SAAS,EAAE,mBAAmB;gBAC9B,WAAW,EAAE,UAAU;aACvB,CAAC;YACF,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa;SACzE,CAAC,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,IAAI,MAAM,EAAE,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;QACxD,MAAM,IAAI,KAAK,CACd,yCAAyC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACjG,CAAC;IACH,CAAC;IAED,IAAI,OAAgB,CAAC;IACrB,IAAI,CAAC;QACJ,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IACjC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CACd,wDACC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CACtD,EAAE,CACF,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,OAAO;YACN,MAAM,EAAE,UAAU;YAClB,KAAK,EAAE,qBAAqB,CAAC,OAAO,EAAE,gCAAgC,CAAC;SACvE,CAAC;IACH,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,yCAAyC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7E,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IACzE,IAAI,SAAS,KAAK,uBAAuB;QAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IACxE,IAAI,SAAS,KAAK,WAAW;QAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;IAE9D,MAAM,gBAAgB,GAAG,OAAO,OAAO,CAAC,iBAAiB,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,CAAC;IACxG,MAAM,MAAM,GAAG,gBAAgB,IAAI,SAAS,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACxE,MAAM,IAAI,KAAK,CAAC,yCAAyC,MAAM,EAAE,CAAC,CAAC;AAAA,CACnE;AAED,uEAAuE;AACvE,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,SAA8B,EAA6B;IACzF,MAAM,SAAS,GAAG,MAAM,iBAAiB,CAAC,oBAAoB,CAAC,CAAC;IAChE,MAAM,MAAM,GAAG,MAAM,6BAA6B,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAErE,SAAS,CAAC,MAAM,CAAC;QAChB,GAAG,EAAE,MAAM,CAAC,uBAAuB;QACnC,YAAY,EAAE,eAAe,MAAM,CAAC,QAAQ,EAAE;KAC9C,CAAC,CAAC;IACH,SAAS,CAAC,UAAU,EAAE,CAAC,yCAAyC,CAAC,CAAC;IAElE,OAAO,uBAAuB,CAAC;QAC9B,IAAI,EAAE,GAAG,EAAE,CAAC,kBAAkB,CAAC,SAAS,CAAC,cAAc,EAAE,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,MAAM,CAAC;QAC7F,eAAe,EAAE,MAAM,CAAC,eAAe;QACvC,gBAAgB,EAAE,MAAM,CAAC,gBAAgB;QACzC,MAAM,EAAE,SAAS,CAAC,MAAM;KACxB,CAAC,CAAC;AAAA,CACH;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,YAAoB,EAA6B;IACtF,IAAI,OAAO,YAAY,KAAK,QAAQ,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC;QAC9D,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAC1C,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,iBAAiB,CAAC,oBAAoB,CAAC,CAAC;IAChE,MAAM,aAAa,GAAG,mBAAmB,CAAC,SAAS,CAAC,cAAc,EAAE,gBAAgB,CAAC,CAAC;IAEtF,MAAM,IAAI,GAAG,IAAI,eAAe,CAAC;QAChC,UAAU,EAAE,eAAe;QAC3B,SAAS,EAAE,mBAAmB;QAC9B,aAAa,EAAE,YAAY;KAC3B,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,aAAa,EAAE;QAC3C,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACR,cAAc,EAAE,mCAAmC;YACnD,MAAM,EAAE,kBAAkB;SAC1B;QACD,IAAI;QACJ,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,wBAAwB,CAAC;KACrD,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QAClB,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,CAAC;YACJ,MAAM,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACzC,CAAC;QAAC,MAAM,CAAC;YACR,4BAA4B;QAC7B,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,6BAA6B,QAAQ,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC9F,CAAC;IAED,IAAI,OAAgB,CAAC;IACrB,IAAI,CAAC;QACJ,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IACjC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CACd,4CAA4C,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACpG,CAAC;IACH,CAAC;IACD,OAAO,qBAAqB,CAAC,OAAO,EAAE,4BAA4B,EAAE,YAAY,CAAC,CAAC;AAAA,CAClF;AAED,MAAM,CAAC,MAAM,gBAAgB,GAA2B;IACvD,EAAE,EAAE,qBAAqB;IACzB,IAAI,EAAE,oCAAoC;IAC1C,KAAK,EAAE,QAAQ;IACf,YAAY,EAAE,CAAC,WAA6B,EAAE,EAAE,CAAC,eAAe,CAAC,WAAW,CAAC,OAAO,CAAC;IACrF,SAAS,EAAE,CAAC,WAA6B,EAAE,EAAE,CAAC,WAAW,CAAC,MAAM;IAChE,YAAY,CAAC,MAAM,EAAE;QACpB,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAC3B,KAAK,CAAC,QAAQ,KAAK,qBAAqB;YACvC,CAAC,CAAC,iBAAiB,CAAC,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,sBAAsB,EAAE,CAAC;YAClE,CAAC,CAAC,KAAK,CACR,CAAC;IAAA,CACF;CACD,CAAC","sourcesContent":["/**\n * xAI Grok OAuth (native device authorization flow).\n *\n * RFC 8628 device-authorization grant with OIDC discovery.\n * Uses the official xAI OAuth client id and scopes.\n */\nimport { applyGrokThinking } from \"../../providers/grok-thinking.ts\";\nimport { pollOAuthDeviceCodeFlow } from \"./device-code.ts\";\nimport type { OAuthCredentials, OAuthLoginCallbacks, OAuthProviderInterface } from \"./types.ts\";\n\nconst XAI_OAUTH_ISSUER = \"https://auth.x.ai\";\nconst XAI_OAUTH_DISCOVERY_URL = `${XAI_OAUTH_ISSUER}/.well-known/openid-configuration`;\nconst XAI_OAUTH_DEVICE_CODE_URL = `${XAI_OAUTH_ISSUER}/oauth2/device/code`;\nconst XAI_OAUTH_CLIENT_ID = \"b1a00492-073a-47ea-816f-4c329264a828\";\nconst XAI_OAUTH_SCOPE =\n\t\"openid profile email offline_access grok-cli:access api:access conversations:read conversations:write workspaces:read workspaces:write\";\nconst XAI_OAUTH_REFERRER = \"grok-build\";\nconst XAI_OAUTH_CLIENT_SURFACE = \"ui\";\n\nconst ACCESS_TOKEN_CLIENT_SKEW_MS = 5 * 60 * 1000;\nconst DISCOVERY_TIMEOUT_MS = 15_000;\nconst TOKEN_REQUEST_TIMEOUT_MS = 20_000;\n\nexport const XAI_OAUTH_PROVIDER_ID = \"xai\";\nconst XAI_OAUTH_API_BASE_URL = \"https://api.x.ai/v1\";\n\ninterface XAIOAuthDiscovery {\n\ttoken_endpoint: string;\n}\n\ninterface XAIDeviceAuthorization {\n\tdeviceCode: string;\n\tuserCode: string;\n\tverificationUriComplete: string;\n\texpiresInSeconds: number;\n\tintervalSeconds: number;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null;\n}\n\nfunction validateXAIEndpoint(url: string, field: string): string {\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(url);\n\t} catch {\n\t\tthrow new Error(`Invalid xAI ${field}: ${url}`);\n\t}\n\tif (parsed.protocol !== \"https:\") {\n\t\tthrow new Error(`Invalid xAI ${field}: ${url}`);\n\t}\n\tconst host = parsed.hostname.toLowerCase();\n\tif (!host || (host !== \"x.ai\" && !host.endsWith(\".x.ai\"))) {\n\t\tthrow new Error(`Invalid xAI ${field}: ${url}`);\n\t}\n\treturn url;\n}\n\nexport function isXAIAccessTokenExpiring(jwt: string, skewSeconds = 0): boolean {\n\ttry {\n\t\tif (typeof jwt !== \"string\" || !jwt.includes(\".\")) return false;\n\t\tconst parts = jwt.split(\".\");\n\t\tif (parts.length < 2) return false;\n\t\tconst payloadPart = parts[1];\n\t\tif (!payloadPart) return false;\n\t\tconst decoded = Buffer.from(payloadPart, \"base64url\").toString(\"utf8\");\n\t\tconst payload: unknown = JSON.parse(decoded);\n\t\tif (!isRecord(payload)) return false;\n\t\tconst exp = payload.exp;\n\t\tif (typeof exp !== \"number\" || !Number.isFinite(exp)) return false;\n\t\tconst now = Math.floor(Date.now() / 1000);\n\t\treturn exp <= now + Math.max(0, Math.floor(skewSeconds));\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nasync function xaiOAuthDiscovery(timeoutMs = DISCOVERY_TIMEOUT_MS): Promise<XAIOAuthDiscovery> {\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetch(XAI_OAUTH_DISCOVERY_URL, {\n\t\t\tmethod: \"GET\",\n\t\t\theaders: { Accept: \"application/json\" },\n\t\t\tsignal: AbortSignal.timeout(timeoutMs),\n\t\t});\n\t} catch (error) {\n\t\tthrow new Error(`xAI OIDC discovery failed: ${error instanceof Error ? error.message : String(error)}`);\n\t}\n\tif (response.status !== 200) {\n\t\tthrow new Error(`xAI OIDC discovery returned status ${response.status}.`);\n\t}\n\tlet payload: unknown;\n\ttry {\n\t\tpayload = await response.json();\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`xAI OIDC discovery returned invalid JSON: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n\tif (!isRecord(payload)) {\n\t\tthrow new Error(\"xAI OIDC discovery response was not a JSON object.\");\n\t}\n\tconst tokenEndpoint = typeof payload.token_endpoint === \"string\" ? payload.token_endpoint.trim() : \"\";\n\tif (!tokenEndpoint) {\n\t\tthrow new Error(\"xAI OIDC discovery response was missing token_endpoint.\");\n\t}\n\tvalidateXAIEndpoint(tokenEndpoint, \"token_endpoint\");\n\treturn { token_endpoint: tokenEndpoint };\n}\n\nfunction parseXAIDeviceAuthorization(payload: unknown): XAIDeviceAuthorization {\n\tif (!isRecord(payload)) {\n\t\tthrow new Error(\"xAI device-code response was not a JSON object.\");\n\t}\n\n\tconst deviceCode = typeof payload.device_code === \"string\" ? payload.device_code.trim() : \"\";\n\tconst userCode = typeof payload.user_code === \"string\" ? payload.user_code.trim() : \"\";\n\tconst verificationUri = typeof payload.verification_uri === \"string\" ? payload.verification_uri.trim() : \"\";\n\tconst verificationUriComplete =\n\t\ttypeof payload.verification_uri_complete === \"string\" ? payload.verification_uri_complete.trim() : \"\";\n\tconst expiresInSeconds = payload.expires_in;\n\tconst intervalSeconds = payload.interval;\n\tif (\n\t\t!deviceCode ||\n\t\t!userCode ||\n\t\t!verificationUri ||\n\t\t!verificationUriComplete ||\n\t\ttypeof expiresInSeconds !== \"number\" ||\n\t\t!Number.isFinite(expiresInSeconds) ||\n\t\texpiresInSeconds <= 0 ||\n\t\ttypeof intervalSeconds !== \"number\" ||\n\t\t!Number.isFinite(intervalSeconds) ||\n\t\tintervalSeconds <= 0\n\t) {\n\t\tthrow new Error(\"xAI device-code response missing or invalid required fields.\");\n\t}\n\n\tvalidateXAIEndpoint(verificationUri, \"verification_uri\");\n\tvalidateXAIEndpoint(verificationUriComplete, \"verification_uri_complete\");\n\treturn {\n\t\tdeviceCode,\n\t\tuserCode,\n\t\tverificationUriComplete,\n\t\texpiresInSeconds,\n\t\tintervalSeconds,\n\t};\n}\n\nfunction parseXAITokenResponse(payload: unknown, label: string, refreshTokenFallback?: string): OAuthCredentials {\n\tif (!isRecord(payload)) {\n\t\tthrow new Error(`${label} was not a JSON object`);\n\t}\n\tconst accessToken = typeof payload.access_token === \"string\" ? payload.access_token : \"\";\n\tconst responseRefreshToken = typeof payload.refresh_token === \"string\" ? payload.refresh_token : \"\";\n\tconst refreshToken = responseRefreshToken || refreshTokenFallback || \"\";\n\tconst expiresInSeconds = payload.expires_in;\n\tif (!accessToken) {\n\t\tthrow new Error(`${label} missing access_token`);\n\t}\n\tif (!refreshToken) {\n\t\tthrow new Error(`${label} missing refresh_token`);\n\t}\n\tif (typeof expiresInSeconds !== \"number\" || !Number.isFinite(expiresInSeconds)) {\n\t\tthrow new Error(`${label} missing expires_in`);\n\t}\n\treturn {\n\t\taccess: accessToken,\n\t\trefresh: refreshToken,\n\t\texpires: Date.now() + expiresInSeconds * 1000 - ACCESS_TOKEN_CLIENT_SKEW_MS,\n\t};\n}\n\nasync function requestXAIDeviceAuthorization(signal?: AbortSignal): Promise<XAIDeviceAuthorization> {\n\tlet response: Response;\n\ttry {\n\t\tconst timeoutSignal = AbortSignal.timeout(TOKEN_REQUEST_TIMEOUT_MS);\n\t\tresponse = await fetch(XAI_OAUTH_DEVICE_CODE_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\tAccept: \"application/json\",\n\t\t\t\t\"x-grok-client-surface\": XAI_OAUTH_CLIENT_SURFACE,\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tclient_id: XAI_OAUTH_CLIENT_ID,\n\t\t\t\tscope: XAI_OAUTH_SCOPE,\n\t\t\t\treferrer: XAI_OAUTH_REFERRER,\n\t\t\t}),\n\t\t\tsignal: signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal,\n\t\t});\n\t} catch (error) {\n\t\tif (signal?.aborted) throw new Error(\"Login cancelled\");\n\t\tthrow new Error(`xAI device-code request failed: ${error instanceof Error ? error.message : String(error)}`);\n\t}\n\n\tif (!response.ok) {\n\t\tlet detail = \"\";\n\t\ttry {\n\t\t\tdetail = (await response.text()).trim();\n\t\t} catch {\n\t\t\t// Ignore body-read failures\n\t\t}\n\t\tthrow new Error(`xAI device-code request failed: ${response.status}${detail ? ` ${detail}` : \"\"}`);\n\t}\n\n\tlet payload: unknown;\n\ttry {\n\t\tpayload = await response.json();\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`xAI device-code response returned invalid JSON: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n\treturn parseXAIDeviceAuthorization(payload);\n}\n\nasync function pollXAIDeviceToken(\n\ttokenEndpoint: string,\n\tdeviceCode: string,\n\tsignal?: AbortSignal,\n): Promise<\n\t| { status: \"pending\" }\n\t| { status: \"slow_down\" }\n\t| { status: \"failed\"; message: string }\n\t| { status: \"complete\"; value: OAuthCredentials }\n> {\n\tlet response: Response;\n\ttry {\n\t\tconst timeoutSignal = AbortSignal.timeout(TOKEN_REQUEST_TIMEOUT_MS);\n\t\tresponse = await fetch(tokenEndpoint, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\tAccept: \"application/json\",\n\t\t\t\t\"x-grok-client-surface\": XAI_OAUTH_CLIENT_SURFACE,\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tgrant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n\t\t\t\tclient_id: XAI_OAUTH_CLIENT_ID,\n\t\t\t\tdevice_code: deviceCode,\n\t\t\t}),\n\t\t\tsignal: signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal,\n\t\t});\n\t} catch (error) {\n\t\tif (signal?.aborted) throw new Error(\"Login cancelled\");\n\t\tthrow new Error(\n\t\t\t`xAI device-code token polling failed: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n\n\tlet payload: unknown;\n\ttry {\n\t\tpayload = await response.json();\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`xAI device-code token polling returned invalid JSON: ${\n\t\t\t\terror instanceof Error ? error.message : String(error)\n\t\t\t}`,\n\t\t);\n\t}\n\n\tif (response.ok) {\n\t\treturn {\n\t\t\tstatus: \"complete\",\n\t\t\tvalue: parseXAITokenResponse(payload, \"xAI device-code token response\"),\n\t\t};\n\t}\n\tif (!isRecord(payload)) {\n\t\tthrow new Error(`xAI device-code token polling failed: ${response.status}`);\n\t}\n\n\tconst errorCode = typeof payload.error === \"string\" ? payload.error : \"\";\n\tif (errorCode === \"authorization_pending\") return { status: \"pending\" };\n\tif (errorCode === \"slow_down\") return { status: \"slow_down\" };\n\n\tconst errorDescription = typeof payload.error_description === \"string\" ? payload.error_description : \"\";\n\tconst detail = errorDescription || errorCode || String(response.status);\n\tthrow new Error(`xAI device-code token polling failed: ${detail}`);\n}\n\n/** Log in to xAI Grok with the RFC 8628 device authorization grant. */\nexport async function loginXAI(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\tconst discovery = await xaiOAuthDiscovery(DISCOVERY_TIMEOUT_MS);\n\tconst device = await requestXAIDeviceAuthorization(callbacks.signal);\n\n\tcallbacks.onAuth({\n\t\turl: device.verificationUriComplete,\n\t\tinstructions: `Enter code: ${device.userCode}`,\n\t});\n\tcallbacks.onProgress?.(\"Waiting for xAI device authorization...\");\n\n\treturn pollOAuthDeviceCodeFlow({\n\t\tpoll: () => pollXAIDeviceToken(discovery.token_endpoint, device.deviceCode, callbacks.signal),\n\t\tintervalSeconds: device.intervalSeconds,\n\t\texpiresInSeconds: device.expiresInSeconds,\n\t\tsignal: callbacks.signal,\n\t});\n}\n\n/**\n * Refresh an xAI OAuth access token using a stored refresh_token.\n * Re-runs OIDC discovery and re-validates the token endpoint before sending.\n */\nexport async function refreshXAIToken(refreshToken: string): Promise<OAuthCredentials> {\n\tif (typeof refreshToken !== \"string\" || !refreshToken.trim()) {\n\t\tthrow new Error(\"missing refresh_token\");\n\t}\n\n\tconst discovery = await xaiOAuthDiscovery(DISCOVERY_TIMEOUT_MS);\n\tconst tokenEndpoint = validateXAIEndpoint(discovery.token_endpoint, \"token_endpoint\");\n\n\tconst body = new URLSearchParams({\n\t\tgrant_type: \"refresh_token\",\n\t\tclient_id: XAI_OAUTH_CLIENT_ID,\n\t\trefresh_token: refreshToken,\n\t});\n\n\tconst response = await fetch(tokenEndpoint, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\tAccept: \"application/json\",\n\t\t},\n\t\tbody,\n\t\tsignal: AbortSignal.timeout(TOKEN_REQUEST_TIMEOUT_MS),\n\t});\n\n\tif (!response.ok) {\n\t\tlet detail = \"\";\n\t\ttry {\n\t\t\tdetail = (await response.text()).trim();\n\t\t} catch {\n\t\t\t// Ignore body-read failures\n\t\t}\n\t\tthrow new Error(`xAI token refresh failed: ${response.status}${detail ? ` ${detail}` : \"\"}`);\n\t}\n\n\tlet payload: unknown;\n\ttry {\n\t\tpayload = await response.json();\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`xAI token refresh returned invalid JSON: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n\treturn parseXAITokenResponse(payload, \"xAI token refresh response\", refreshToken);\n}\n\nexport const xaiOAuthProvider: OAuthProviderInterface = {\n\tid: XAI_OAUTH_PROVIDER_ID,\n\tname: \"xAI Grok (SuperGrok or X Premium+)\",\n\tlogin: loginXAI,\n\trefreshToken: (credentials: OAuthCredentials) => refreshXAIToken(credentials.refresh),\n\tgetApiKey: (credentials: OAuthCredentials) => credentials.access,\n\tmodifyModels(models) {\n\t\treturn models.map((model) =>\n\t\t\tmodel.provider === XAI_OAUTH_PROVIDER_ID\n\t\t\t\t? applyGrokThinking({ ...model, baseUrl: XAI_OAUTH_API_BASE_URL })\n\t\t\t\t: model,\n\t\t);\n\t},\n};\n"]}
1
+ {"version":3,"file":"xai.js","sourceRoot":"","sources":["../../../src/utils/oauth/xai.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * xAI Grok OAuth (native device authorization flow).\n *\n * RFC 8628 device-authorization grant with OIDC discovery.\n * Uses the official xAI OAuth client id and scopes.\n */\nimport { applyGrokThinking } from \"../../providers/grok-thinking.ts\";\nimport { pollOAuthDeviceCodeFlow } from \"./device-code.ts\";\nimport type { OAuthCredentials, OAuthLoginCallbacks, OAuthProviderInterface } from \"./types.ts\";\n\nconst XAI_OAUTH_ISSUER = \"https://auth.x.ai\";\nconst XAI_OAUTH_DISCOVERY_URL = `${XAI_OAUTH_ISSUER}/.well-known/openid-configuration`;\nconst XAI_OAUTH_DEVICE_CODE_URL = `${XAI_OAUTH_ISSUER}/oauth2/device/code`;\nconst XAI_OAUTH_CLIENT_ID = \"b1a00492-073a-47ea-816f-4c329264a828\"; // gitleaks:allow -- public native-app OAuth client id\nconst XAI_OAUTH_SCOPE =\n\t\"openid profile email offline_access grok-cli:access api:access conversations:read conversations:write workspaces:read workspaces:write\";\nconst XAI_OAUTH_REFERRER = \"grok-build\";\nconst XAI_OAUTH_CLIENT_SURFACE = \"ui\";\n\nconst ACCESS_TOKEN_CLIENT_SKEW_MS = 5 * 60 * 1000;\nconst DISCOVERY_TIMEOUT_MS = 15_000;\nconst TOKEN_REQUEST_TIMEOUT_MS = 20_000;\n\nexport const XAI_OAUTH_PROVIDER_ID = \"xai\";\nconst XAI_OAUTH_API_BASE_URL = \"https://api.x.ai/v1\";\n\ninterface XAIOAuthDiscovery {\n\ttoken_endpoint: string;\n}\n\ninterface XAIDeviceAuthorization {\n\tdeviceCode: string;\n\tuserCode: string;\n\tverificationUriComplete: string;\n\texpiresInSeconds: number;\n\tintervalSeconds: number;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null;\n}\n\nfunction validateXAIEndpoint(url: string, field: string): string {\n\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(url);\n\t} catch {\n\t\tthrow new Error(`Invalid xAI ${field}: ${url}`);\n\t}\n\tif (parsed.protocol !== \"https:\") {\n\t\tthrow new Error(`Invalid xAI ${field}: ${url}`);\n\t}\n\tconst host = parsed.hostname.toLowerCase();\n\tif (!host || (host !== \"x.ai\" && !host.endsWith(\".x.ai\"))) {\n\t\tthrow new Error(`Invalid xAI ${field}: ${url}`);\n\t}\n\treturn url;\n}\n\nexport function isXAIAccessTokenExpiring(jwt: string, skewSeconds = 0): boolean {\n\ttry {\n\t\tif (typeof jwt !== \"string\" || !jwt.includes(\".\")) return false;\n\t\tconst parts = jwt.split(\".\");\n\t\tif (parts.length < 2) return false;\n\t\tconst payloadPart = parts[1];\n\t\tif (!payloadPart) return false;\n\t\tconst decoded = Buffer.from(payloadPart, \"base64url\").toString(\"utf8\");\n\t\tconst payload: unknown = JSON.parse(decoded);\n\t\tif (!isRecord(payload)) return false;\n\t\tconst exp = payload.exp;\n\t\tif (typeof exp !== \"number\" || !Number.isFinite(exp)) return false;\n\t\tconst now = Math.floor(Date.now() / 1000);\n\t\treturn exp <= now + Math.max(0, Math.floor(skewSeconds));\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nasync function xaiOAuthDiscovery(timeoutMs = DISCOVERY_TIMEOUT_MS): Promise<XAIOAuthDiscovery> {\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetch(XAI_OAUTH_DISCOVERY_URL, {\n\t\t\tmethod: \"GET\",\n\t\t\theaders: { Accept: \"application/json\" },\n\t\t\tsignal: AbortSignal.timeout(timeoutMs),\n\t\t});\n\t} catch (error) {\n\t\tthrow new Error(`xAI OIDC discovery failed: ${error instanceof Error ? error.message : String(error)}`);\n\t}\n\tif (response.status !== 200) {\n\t\tthrow new Error(`xAI OIDC discovery returned status ${response.status}.`);\n\t}\n\tlet payload: unknown;\n\ttry {\n\t\tpayload = await response.json();\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`xAI OIDC discovery returned invalid JSON: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n\tif (!isRecord(payload)) {\n\t\tthrow new Error(\"xAI OIDC discovery response was not a JSON object.\");\n\t}\n\tconst tokenEndpoint = typeof payload.token_endpoint === \"string\" ? payload.token_endpoint.trim() : \"\";\n\tif (!tokenEndpoint) {\n\t\tthrow new Error(\"xAI OIDC discovery response was missing token_endpoint.\");\n\t}\n\tvalidateXAIEndpoint(tokenEndpoint, \"token_endpoint\");\n\treturn { token_endpoint: tokenEndpoint };\n}\n\nfunction parseXAIDeviceAuthorization(payload: unknown): XAIDeviceAuthorization {\n\tif (!isRecord(payload)) {\n\t\tthrow new Error(\"xAI device-code response was not a JSON object.\");\n\t}\n\n\tconst deviceCode = typeof payload.device_code === \"string\" ? payload.device_code.trim() : \"\";\n\tconst userCode = typeof payload.user_code === \"string\" ? payload.user_code.trim() : \"\";\n\tconst verificationUri = typeof payload.verification_uri === \"string\" ? payload.verification_uri.trim() : \"\";\n\tconst verificationUriComplete =\n\t\ttypeof payload.verification_uri_complete === \"string\" ? payload.verification_uri_complete.trim() : \"\";\n\tconst expiresInSeconds = payload.expires_in;\n\tconst intervalSeconds = payload.interval;\n\tif (\n\t\t!deviceCode ||\n\t\t!userCode ||\n\t\t!verificationUri ||\n\t\t!verificationUriComplete ||\n\t\ttypeof expiresInSeconds !== \"number\" ||\n\t\t!Number.isFinite(expiresInSeconds) ||\n\t\texpiresInSeconds <= 0 ||\n\t\ttypeof intervalSeconds !== \"number\" ||\n\t\t!Number.isFinite(intervalSeconds) ||\n\t\tintervalSeconds <= 0\n\t) {\n\t\tthrow new Error(\"xAI device-code response missing or invalid required fields.\");\n\t}\n\n\tvalidateXAIEndpoint(verificationUri, \"verification_uri\");\n\tvalidateXAIEndpoint(verificationUriComplete, \"verification_uri_complete\");\n\treturn {\n\t\tdeviceCode,\n\t\tuserCode,\n\t\tverificationUriComplete,\n\t\texpiresInSeconds,\n\t\tintervalSeconds,\n\t};\n}\n\nfunction parseXAITokenResponse(payload: unknown, label: string, refreshTokenFallback?: string): OAuthCredentials {\n\tif (!isRecord(payload)) {\n\t\tthrow new Error(`${label} was not a JSON object`);\n\t}\n\tconst accessToken = typeof payload.access_token === \"string\" ? payload.access_token : \"\";\n\tconst responseRefreshToken = typeof payload.refresh_token === \"string\" ? payload.refresh_token : \"\";\n\tconst refreshToken = responseRefreshToken || refreshTokenFallback || \"\";\n\tconst expiresInSeconds = payload.expires_in;\n\tif (!accessToken) {\n\t\tthrow new Error(`${label} missing access_token`);\n\t}\n\tif (!refreshToken) {\n\t\tthrow new Error(`${label} missing refresh_token`);\n\t}\n\tif (typeof expiresInSeconds !== \"number\" || !Number.isFinite(expiresInSeconds)) {\n\t\tthrow new Error(`${label} missing expires_in`);\n\t}\n\treturn {\n\t\taccess: accessToken,\n\t\trefresh: refreshToken,\n\t\texpires: Date.now() + expiresInSeconds * 1000 - ACCESS_TOKEN_CLIENT_SKEW_MS,\n\t};\n}\n\nasync function requestXAIDeviceAuthorization(signal?: AbortSignal): Promise<XAIDeviceAuthorization> {\n\tlet response: Response;\n\ttry {\n\t\tconst timeoutSignal = AbortSignal.timeout(TOKEN_REQUEST_TIMEOUT_MS);\n\t\tresponse = await fetch(XAI_OAUTH_DEVICE_CODE_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\tAccept: \"application/json\",\n\t\t\t\t\"x-grok-client-surface\": XAI_OAUTH_CLIENT_SURFACE,\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tclient_id: XAI_OAUTH_CLIENT_ID,\n\t\t\t\tscope: XAI_OAUTH_SCOPE,\n\t\t\t\treferrer: XAI_OAUTH_REFERRER,\n\t\t\t}),\n\t\t\tsignal: signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal,\n\t\t});\n\t} catch (error) {\n\t\tif (signal?.aborted) throw new Error(\"Login cancelled\");\n\t\tthrow new Error(`xAI device-code request failed: ${error instanceof Error ? error.message : String(error)}`);\n\t}\n\n\tif (!response.ok) {\n\t\tlet detail = \"\";\n\t\ttry {\n\t\t\tdetail = (await response.text()).trim();\n\t\t} catch {\n\t\t\t// Ignore body-read failures\n\t\t}\n\t\tthrow new Error(`xAI device-code request failed: ${response.status}${detail ? ` ${detail}` : \"\"}`);\n\t}\n\n\tlet payload: unknown;\n\ttry {\n\t\tpayload = await response.json();\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`xAI device-code response returned invalid JSON: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n\treturn parseXAIDeviceAuthorization(payload);\n}\n\nasync function pollXAIDeviceToken(\n\ttokenEndpoint: string,\n\tdeviceCode: string,\n\tsignal?: AbortSignal,\n): Promise<\n\t| { status: \"pending\" }\n\t| { status: \"slow_down\" }\n\t| { status: \"failed\"; message: string }\n\t| { status: \"complete\"; value: OAuthCredentials }\n> {\n\tlet response: Response;\n\ttry {\n\t\tconst timeoutSignal = AbortSignal.timeout(TOKEN_REQUEST_TIMEOUT_MS);\n\t\tresponse = await fetch(tokenEndpoint, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\tAccept: \"application/json\",\n\t\t\t\t\"x-grok-client-surface\": XAI_OAUTH_CLIENT_SURFACE,\n\t\t\t},\n\t\t\tbody: new URLSearchParams({\n\t\t\t\tgrant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n\t\t\t\tclient_id: XAI_OAUTH_CLIENT_ID,\n\t\t\t\tdevice_code: deviceCode,\n\t\t\t}),\n\t\t\tsignal: signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal,\n\t\t});\n\t} catch (error) {\n\t\tif (signal?.aborted) throw new Error(\"Login cancelled\");\n\t\tthrow new Error(\n\t\t\t`xAI device-code token polling failed: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n\n\tlet payload: unknown;\n\ttry {\n\t\tpayload = await response.json();\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`xAI device-code token polling returned invalid JSON: ${\n\t\t\t\terror instanceof Error ? error.message : String(error)\n\t\t\t}`,\n\t\t);\n\t}\n\n\tif (response.ok) {\n\t\treturn {\n\t\t\tstatus: \"complete\",\n\t\t\tvalue: parseXAITokenResponse(payload, \"xAI device-code token response\"),\n\t\t};\n\t}\n\tif (!isRecord(payload)) {\n\t\tthrow new Error(`xAI device-code token polling failed: ${response.status}`);\n\t}\n\n\tconst errorCode = typeof payload.error === \"string\" ? payload.error : \"\";\n\tif (errorCode === \"authorization_pending\") return { status: \"pending\" };\n\tif (errorCode === \"slow_down\") return { status: \"slow_down\" };\n\n\tconst errorDescription = typeof payload.error_description === \"string\" ? payload.error_description : \"\";\n\tconst detail = errorDescription || errorCode || String(response.status);\n\tthrow new Error(`xAI device-code token polling failed: ${detail}`);\n}\n\n/** Log in to xAI Grok with the RFC 8628 device authorization grant. */\nexport async function loginXAI(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n\tconst discovery = await xaiOAuthDiscovery(DISCOVERY_TIMEOUT_MS);\n\tconst device = await requestXAIDeviceAuthorization(callbacks.signal);\n\n\tcallbacks.onAuth({\n\t\turl: device.verificationUriComplete,\n\t\tinstructions: `Enter code: ${device.userCode}`,\n\t});\n\tcallbacks.onProgress?.(\"Waiting for xAI device authorization...\");\n\n\treturn pollOAuthDeviceCodeFlow({\n\t\tpoll: () => pollXAIDeviceToken(discovery.token_endpoint, device.deviceCode, callbacks.signal),\n\t\tintervalSeconds: device.intervalSeconds,\n\t\texpiresInSeconds: device.expiresInSeconds,\n\t\tsignal: callbacks.signal,\n\t});\n}\n\n/**\n * Refresh an xAI OAuth access token using a stored refresh_token.\n * Re-runs OIDC discovery and re-validates the token endpoint before sending.\n */\nexport async function refreshXAIToken(refreshToken: string): Promise<OAuthCredentials> {\n\tif (typeof refreshToken !== \"string\" || !refreshToken.trim()) {\n\t\tthrow new Error(\"missing refresh_token\");\n\t}\n\n\tconst discovery = await xaiOAuthDiscovery(DISCOVERY_TIMEOUT_MS);\n\tconst tokenEndpoint = validateXAIEndpoint(discovery.token_endpoint, \"token_endpoint\");\n\n\tconst body = new URLSearchParams({\n\t\tgrant_type: \"refresh_token\",\n\t\tclient_id: XAI_OAUTH_CLIENT_ID,\n\t\trefresh_token: refreshToken,\n\t});\n\n\tconst response = await fetch(tokenEndpoint, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\tAccept: \"application/json\",\n\t\t},\n\t\tbody,\n\t\tsignal: AbortSignal.timeout(TOKEN_REQUEST_TIMEOUT_MS),\n\t});\n\n\tif (!response.ok) {\n\t\tlet detail = \"\";\n\t\ttry {\n\t\t\tdetail = (await response.text()).trim();\n\t\t} catch {\n\t\t\t// Ignore body-read failures\n\t\t}\n\t\tthrow new Error(`xAI token refresh failed: ${response.status}${detail ? ` ${detail}` : \"\"}`);\n\t}\n\n\tlet payload: unknown;\n\ttry {\n\t\tpayload = await response.json();\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`xAI token refresh returned invalid JSON: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n\treturn parseXAITokenResponse(payload, \"xAI token refresh response\", refreshToken);\n}\n\nexport const xaiOAuthProvider: OAuthProviderInterface = {\n\tid: XAI_OAUTH_PROVIDER_ID,\n\tname: \"xAI Grok (SuperGrok or X Premium+)\",\n\tlogin: loginXAI,\n\trefreshToken: (credentials: OAuthCredentials) => refreshXAIToken(credentials.refresh),\n\tgetApiKey: (credentials: OAuthCredentials) => credentials.access,\n\tmodifyModels(models) {\n\t\treturn models.map((model) =>\n\t\t\tmodel.provider === XAI_OAUTH_PROVIDER_ID\n\t\t\t\t? applyGrokThinking({ ...model, baseUrl: XAI_OAUTH_API_BASE_URL })\n\t\t\t\t: model,\n\t\t);\n\t},\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omk-ai",
3
- "version": "0.96.2",
3
+ "version": "0.98.0",
4
4
  "description": "Unified LLM API with automatic model discovery and provider configuration",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",