From f1319448ac5dcfb047e8f107a585ad28176dd491 Mon Sep 17 00:00:00 2001 From: diegosouzapw Date: Tue, 17 Feb 2026 03:46:24 -0300 Subject: [PATCH] =?UTF-8?q?refactor(types):=20Wave=203c=20=E2=80=94=20OAut?= =?UTF-8?q?h=20services=20+=20server=20utils=20typed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - oauth.ts: typed OAuthService class with config field, all method params - antigravity.ts: typed AntigravityService class + all OAuth flow params - iflow.ts: typed IFlowService class + Basic Auth flow params - gemini.ts: typed GeminiCLIService class + project ID fetching - qwen.ts: typed QwenService class + device code flow params - cursor.ts: typed CursorService class + checksum/headers params - server.ts: typed startLocalServer return + waitForCallback - Fixed resolve() calls to resolve(undefined) for strict Promise TS errors: 490 → 419 (-71) Total reduction: 984 → 419 (-565, 57.4%) Build: ✅ Tests: 368/368 ✅ --- src/lib/oauth/services/antigravity.ts | 26 ++++++++++++++------------ src/lib/oauth/services/cursor.ts | 10 ++++++---- src/lib/oauth/services/gemini.ts | 18 ++++++++++-------- src/lib/oauth/services/iflow.ts | 16 +++++++++------- src/lib/oauth/services/oauth.ts | 20 +++++++++++--------- src/lib/oauth/services/qwen.ts | 10 ++++++---- src/lib/oauth/utils/server.ts | 14 +++++++------- 7 files changed, 63 insertions(+), 51 deletions(-) diff --git a/src/lib/oauth/services/antigravity.ts b/src/lib/oauth/services/antigravity.ts index c4169c6dd0..909c78a21d 100644 --- a/src/lib/oauth/services/antigravity.ts +++ b/src/lib/oauth/services/antigravity.ts @@ -10,6 +10,8 @@ import { spinner as createSpinner } from "../utils/ui"; * Uses standard OAuth2 Authorization Code flow (similar to Gemini) */ export class AntigravityService { + config: any; + constructor() { this.config = ANTIGRAVITY_CONFIG; } @@ -17,7 +19,7 @@ export class AntigravityService { /** * Build Antigravity authorization URL */ - buildAuthUrl(redirectUri, state) { + buildAuthUrl(redirectUri: string, state: string) { const params = new URLSearchParams({ client_id: this.config.clientId, response_type: "code", @@ -34,7 +36,7 @@ export class AntigravityService { /** * Exchange authorization code for tokens */ - async exchangeCode(code, redirectUri) { + async exchangeCode(code: string, redirectUri: string) { const response = await fetch(this.config.tokenUrl, { method: "POST", headers: { @@ -61,7 +63,7 @@ export class AntigravityService { /** * Get user info from Google */ - async getUserInfo(accessToken) { + async getUserInfo(accessToken: string) { const response = await fetch(`${this.config.userInfoUrl}?alt=json`, { headers: { Authorization: `Bearer ${accessToken}`, @@ -80,7 +82,7 @@ export class AntigravityService { /** * Get common headers for Antigravity API calls */ - getApiHeaders(accessToken) { + getApiHeaders(accessToken: string) { return { Authorization: `Bearer ${accessToken}`, "Content-Type": "application/json", @@ -104,7 +106,7 @@ export class AntigravityService { /** * Fetch Project ID and Tier from loadCodeAssist API */ - async loadCodeAssist(accessToken) { + async loadCodeAssist(accessToken: string) { const response = await fetch(this.config.loadCodeAssistEndpoint, { method: "POST", headers: this.getApiHeaders(accessToken), @@ -141,7 +143,7 @@ export class AntigravityService { /** * Onboard user to enable Gemini Code Assist for the project */ - async onboardUser(accessToken, projectId, tierId) { + async onboardUser(accessToken: string, projectId: string, tierId: string) { const response = await fetch(this.config.onboardUserEndpoint, { method: "POST", headers: this.getApiHeaders(accessToken), @@ -163,7 +165,7 @@ export class AntigravityService { /** * Complete onboarding flow with retry */ - async completeOnboarding(accessToken, projectId, tierId, maxRetries = 10) { + async completeOnboarding(accessToken: string, projectId: string, tierId: string, maxRetries = 10) { for (let i = 0; i < maxRetries; i++) { const result = await this.onboardUser(accessToken, projectId, tierId); @@ -191,7 +193,7 @@ export class AntigravityService { /** * Fetch Project ID from loadCodeAssist API (legacy method for compatibility) */ - async fetchProjectId(accessToken) { + async fetchProjectId(accessToken: string) { const { projectId } = await this.loadCodeAssist(accessToken); if (!projectId) { throw new Error("No cloudaicompanionProject found in response"); @@ -202,7 +204,7 @@ export class AntigravityService { /** * Save Antigravity tokens to server */ - async saveTokens(tokens, userInfo, projectId) { + async saveTokens(tokens: any, userInfo: any, projectId: string) { const { server, token, userId } = getServerCredentials(); const response = await fetch(`${server}/api/cli/providers/antigravity`, { @@ -240,7 +242,7 @@ export class AntigravityService { spinner.text = "Starting local server..."; // Start local server for callback - let callbackParams = null; + let callbackParams: any = null; const { port, close } = await startLocalServer((params) => { callbackParams = params; }); @@ -272,7 +274,7 @@ export class AntigravityService { if (callbackParams) { clearInterval(checkInterval); clearTimeout(timeout); - resolve(); + resolve(undefined); } }, 100); }); @@ -323,7 +325,7 @@ export class AntigravityService { `Antigravity connected successfully! (${userInfo.email}, Project: ${finalProjectId})` ); return true; - } catch (error) { + } catch (error: any) { spinner.fail(`Failed: ${error.message}`); throw error; } diff --git a/src/lib/oauth/services/cursor.ts b/src/lib/oauth/services/cursor.ts index b06ad9cf26..82b4639b74 100644 --- a/src/lib/oauth/services/cursor.ts +++ b/src/lib/oauth/services/cursor.ts @@ -15,6 +15,8 @@ import { CURSOR_CONFIG } from "../constants/oauth"; */ export class CursorService { + config: any; + constructor() { this.config = CURSOR_CONFIG; } @@ -24,7 +26,7 @@ export class CursorService { * Algorithm: XOR timestamp bytes with rolling key (initial 165), then base64 encode * Format: {encoded_timestamp},{machineId} */ - generateChecksum(machineId) { + generateChecksum(machineId: string) { const timestamp = Math.floor(Date.now() / 1000).toString(); let key = 165; const encoded = []; @@ -42,7 +44,7 @@ export class CursorService { /** * Build request headers for Cursor API */ - buildHeaders(accessToken, machineId, ghostMode = false) { + buildHeaders(accessToken: string, machineId: string, ghostMode = false) { const checksum = this.generateChecksum(machineId); return { @@ -92,7 +94,7 @@ export class CursorService { * @param {string} accessToken - Access token from state.vscdb * @param {string} machineId - Machine ID from state.vscdb */ - async validateImportToken(accessToken, machineId) { + async validateImportToken(accessToken: string, machineId: string) { // Basic validation if (!accessToken || typeof accessToken !== "string") { throw new Error("Access token is required"); @@ -128,7 +130,7 @@ export class CursorService { * Extract user info from token if possible * Cursor tokens may contain encoded user info */ - extractUserInfo(accessToken) { + extractUserInfo(accessToken: string) { try { // Try to decode as JWT const parts = accessToken.split("."); diff --git a/src/lib/oauth/services/gemini.ts b/src/lib/oauth/services/gemini.ts index 1c7110c3cd..373f588dda 100644 --- a/src/lib/oauth/services/gemini.ts +++ b/src/lib/oauth/services/gemini.ts @@ -10,6 +10,8 @@ import { spinner as createSpinner } from "../utils/ui"; * Uses standard OAuth2 Authorization Code flow (no PKCE) */ export class GeminiCLIService { + config: any; + constructor() { this.config = GEMINI_CONFIG; } @@ -17,7 +19,7 @@ export class GeminiCLIService { /** * Build Gemini CLI authorization URL */ - buildAuthUrl(redirectUri, state) { + buildAuthUrl(redirectUri: string, state: string) { const params = new URLSearchParams({ client_id: this.config.clientId, response_type: "code", @@ -34,7 +36,7 @@ export class GeminiCLIService { /** * Exchange authorization code for tokens */ - async exchangeCode(code, redirectUri) { + async exchangeCode(code: string, redirectUri: string) { const response = await fetch(this.config.tokenUrl, { method: "POST", headers: { @@ -61,7 +63,7 @@ export class GeminiCLIService { /** * Fetch project ID from Google Cloud Code Assist */ - async fetchProjectId(accessToken) { + async fetchProjectId(accessToken: string) { const response = await fetch("https://cloudcode-pa.googleapis.com/v1internal:loadCodeAssist", { method: "POST", headers: { @@ -109,7 +111,7 @@ export class GeminiCLIService { /** * Get user info from Google */ - async getUserInfo(accessToken) { + async getUserInfo(accessToken: string) { const response = await fetch(`${this.config.userInfoUrl}?alt=json`, { headers: { Authorization: `Bearer ${accessToken}`, @@ -128,7 +130,7 @@ export class GeminiCLIService { /** * Save Gemini CLI tokens to server */ - async saveTokens(tokens, userInfo, projectId) { + async saveTokens(tokens: any, userInfo: any, projectId: string) { const { server, token, userId } = getServerCredentials(); const response = await fetch(`${server}/api/cli/providers/gemini-cli`, { @@ -166,7 +168,7 @@ export class GeminiCLIService { spinner.text = "Starting local server..."; // Start local server for callback - let callbackParams = null; + let callbackParams: any = null; const { port, close } = await startLocalServer((params) => { callbackParams = params; }); @@ -198,7 +200,7 @@ export class GeminiCLIService { if (callbackParams) { clearInterval(checkInterval); clearTimeout(timeout); - resolve(); + resolve(undefined); } }, 100); }); @@ -237,7 +239,7 @@ export class GeminiCLIService { `Gemini CLI connected successfully! (${userInfo.email}, Project: ${projectId})` ); return true; - } catch (error) { + } catch (error: any) { spinner.fail(`Failed: ${error.message}`); throw error; } diff --git a/src/lib/oauth/services/iflow.ts b/src/lib/oauth/services/iflow.ts index 951dee0bc6..91b32927d9 100644 --- a/src/lib/oauth/services/iflow.ts +++ b/src/lib/oauth/services/iflow.ts @@ -10,6 +10,8 @@ import { spinner as createSpinner } from "../utils/ui"; * Uses Authorization Code flow with Basic Auth */ export class IFlowService { + config: any; + constructor() { this.config = IFLOW_CONFIG; } @@ -17,7 +19,7 @@ export class IFlowService { /** * Build iFlow authorization URL */ - buildAuthUrl(redirectUri, state) { + buildAuthUrl(redirectUri: string, state: string) { const params = new URLSearchParams({ loginMethod: this.config.extraParams.loginMethod, type: this.config.extraParams.type, @@ -32,7 +34,7 @@ export class IFlowService { /** * Exchange authorization code for tokens */ - async exchangeCode(code, redirectUri) { + async exchangeCode(code: string, redirectUri: string) { // Create Basic Auth header const basicAuth = Buffer.from(`${this.config.clientId}:${this.config.clientSecret}`).toString( "base64" @@ -65,7 +67,7 @@ export class IFlowService { /** * Get user info from iFlow */ - async getUserInfo(accessToken) { + async getUserInfo(accessToken: string) { const response = await fetch( `${this.config.userInfoUrl}?accessToken=${encodeURIComponent(accessToken)}`, { @@ -92,7 +94,7 @@ export class IFlowService { /** * Save iFlow tokens to server */ - async saveTokens(tokens, userInfo) { + async saveTokens(tokens: any, userInfo: any) { const { server, token, userId } = getServerCredentials(); const response = await fetch(`${server}/api/cli/providers/iflow`, { @@ -129,7 +131,7 @@ export class IFlowService { spinner.text = "Starting local server..."; // Start local server for callback - let callbackParams = null; + let callbackParams: any = null; const { port, close } = await startLocalServer((params) => { callbackParams = params; }); @@ -161,7 +163,7 @@ export class IFlowService { if (callbackParams) { clearInterval(checkInterval); clearTimeout(timeout); - resolve(); + resolve(undefined); } }, 100); }); @@ -193,7 +195,7 @@ export class IFlowService { spinner.succeed(`iFlow connected successfully! (${userInfo.email || userInfo.phone})`); return true; - } catch (error) { + } catch (error: any) { spinner.fail(`Failed: ${error.message}`); throw error; } diff --git a/src/lib/oauth/services/oauth.ts b/src/lib/oauth/services/oauth.ts index 1ddad570a9..08eada6c83 100644 --- a/src/lib/oauth/services/oauth.ts +++ b/src/lib/oauth/services/oauth.ts @@ -8,14 +8,16 @@ import { OAUTH_TIMEOUT } from "../constants/oauth"; * Generic OAuth Authorization Code Flow with PKCE */ export class OAuthService { - constructor(config) { + config: any; + + constructor(config: any) { this.config = config; } /** * Build authorization URL */ - buildAuthUrl(redirectUri, state, codeChallenge, extraParams = {}) { + buildAuthUrl(redirectUri: string, state: string, codeChallenge: string, extraParams: Record = {}) { const params = new URLSearchParams({ client_id: this.config.clientId, response_type: "code", @@ -32,11 +34,11 @@ export class OAuthService { /** * Start local server and wait for callback */ - async startAuthFlow(authUrl, providerName) { + async startAuthFlow(authUrl: string | null, providerName: string) { const spinner = createSpinner("Starting local server...").start(); // Start local server for callback - let callbackParams = null; + let callbackParams: any = null; const { port, close } = await startLocalServer((params) => { callbackParams = params; }); @@ -60,7 +62,7 @@ export class OAuthService { if (callbackParams) { clearInterval(checkInterval); clearTimeout(timeout); - resolve(); + resolve(undefined); } }, 100); }); @@ -85,9 +87,9 @@ export class OAuthService { * Exchange authorization code for tokens */ async exchangeCode( - code, - redirectUri, - codeVerifier, + code: string, + redirectUri: string, + codeVerifier: string, contentType = "application/x-www-form-urlencoded" ) { const body = @@ -127,7 +129,7 @@ export class OAuthService { /** * Complete OAuth flow */ - async authenticate(providerName, buildAuthUrlFn) { + async authenticate(providerName: string, buildAuthUrlFn: (redirectUri: string, state: string, codeChallenge: string) => string) { // Generate PKCE const { codeVerifier, codeChallenge, state } = generatePKCE(); diff --git a/src/lib/oauth/services/qwen.ts b/src/lib/oauth/services/qwen.ts index 4b98a6c6f7..547059ef82 100644 --- a/src/lib/oauth/services/qwen.ts +++ b/src/lib/oauth/services/qwen.ts @@ -9,6 +9,8 @@ import { spinner as createSpinner } from "../utils/ui"; * Uses Device Code Flow with PKCE */ export class QwenService { + config: any; + constructor() { this.config = QWEN_CONFIG; } @@ -16,7 +18,7 @@ export class QwenService { /** * Request device code */ - async requestDeviceCode(codeChallenge) { + async requestDeviceCode(codeChallenge: string) { const response = await fetch(this.config.deviceCodeUrl, { method: "POST", headers: { @@ -42,7 +44,7 @@ export class QwenService { /** * Poll for token */ - async pollForToken(deviceCode, codeVerifier, interval = 5) { + async pollForToken(deviceCode: string, codeVerifier: string, interval = 5) { const maxAttempts = 60; // 5 minutes const pollInterval = interval * 1000; @@ -89,7 +91,7 @@ export class QwenService { /** * Save Qwen tokens to server */ - async saveTokens(tokens) { + async saveTokens(tokens: any) { const { server, token, userId } = getServerCredentials(); const response = await fetch(`${server}/api/cli/providers/qwen`, { @@ -161,7 +163,7 @@ export class QwenService { spinner.succeed("Qwen connected successfully!"); return true; - } catch (error) { + } catch (error: any) { spinner.fail(`Failed: ${error.message}`); throw error; } diff --git a/src/lib/oauth/utils/server.ts b/src/lib/oauth/utils/server.ts index c4946f968b..4698bd9ed3 100644 --- a/src/lib/oauth/utils/server.ts +++ b/src/lib/oauth/utils/server.ts @@ -7,10 +7,10 @@ import { URL } from "url"; * @param {number} fixedPort - Optional fixed port number (default: random) * @returns {Promise<{server: http.Server, port: number, close: Function}>} */ -export function startLocalServer(onCallback, fixedPort = null) { +export function startLocalServer(onCallback: (params: Record) => void, fixedPort: number | null = null): Promise<{ server: any; port: number; close: () => void }> { return new Promise((resolve, reject) => { const server = http.createServer((req, res) => { - const url = new URL(req.url, `http://localhost`); + const url = new URL(req.url || "/", `http://localhost`); if (url.pathname === "/callback" || url.pathname === "/auth/callback") { const params = Object.fromEntries(url.searchParams); @@ -67,15 +67,15 @@ export function startLocalServer(onCallback, fixedPort = null) { // Listen on fixed port or find available port const portToUse = fixedPort || 0; server.listen(portToUse, "127.0.0.1", () => { - const { port } = server.address(); + const addr = server.address() as { port: number }; resolve({ server, - port, + port: addr.port, close: () => server.close(), }); }); - server.on("error", (err) => { + server.on("error", (err: any) => { if (err.code === "EADDRINUSE" && fixedPort) { reject( new Error( @@ -105,7 +105,7 @@ export function waitForCallback(timeoutMs = 300000) { } }, timeoutMs); - const onCallback = (params) => { + const onCallback = (params: Record) => { if (!resolved) { resolved = true; clearTimeout(timeout); @@ -114,6 +114,6 @@ export function waitForCallback(timeoutMs = 300000) { }; // Return the callback function - resolve.__onCallback = onCallback; + (resolve as any).__onCallback = onCallback; }); }