import { OAuth2Client } from 'google-auth-library';
import * as fs from 'fs/promises';
import { getKeysFilePath, generateCredentialsErrorMessage, OAuthCredentials } from './utils.js';
async function loadCredentialsFromFile(): Promise<OAuthCredentials> {
const keysContent = await fs.readFile(getKeysFilePath(), "utf-8");
const keys = JSON.parse(keysContent);
if (keys.installed) {
// Standard OAuth credentials file format
const { client_id, client_secret, redirect_uris } = keys.installed;
return { client_id, client_secret, redirect_uris };
} else if (keys.client_id && keys.client_secret) {
// Direct format
return {
client_id: keys.client_id,
client_secret: keys.client_secret,
redirect_uris: keys.redirect_uris || ['http://localhost:3000/oauth2callback']
};
} else {
throw new Error('Invalid credentials file format. Expected either "installed" object or direct client_id/client_secret fields.');
}
}
async function loadCredentialsWithFallback(): Promise<OAuthCredentials> {
// First check for direct environment variables
const clientId = process.env.GOOGLE_CLIENT_ID;
const clientSecret = process.env.GOOGLE_CLIENT_SECRET;
if (clientId && clientSecret) {
// Use environment variables directly - no JSON file needed!
return {
client_id: clientId,
client_secret: clientSecret,
redirect_uris: ['http://localhost:3000/oauth2callback']
};
}
// Otherwise, load credentials from file (CLI param, env var, or default path)
try {
return await loadCredentialsFromFile();
} catch (fileError) {
// Generate helpful error message
const errorMessage = generateCredentialsErrorMessage();
throw new Error(`${errorMessage}\n\nOriginal error: ${fileError instanceof Error ? fileError.message : fileError}`);
}
}
export async function initializeOAuth2Client(): Promise<OAuth2Client> {
try {
const credentials = await loadCredentialsWithFallback();
// Use the first redirect URI as the default for the base client
const oauth2Client = new OAuth2Client({
clientId: credentials.client_id,
clientSecret: credentials.client_secret,
redirectUri: credentials.redirect_uris[0],
});
return oauth2Client;
} catch (error) {
throw new Error(`Error loading OAuth keys: ${error instanceof Error ? error.message : error}`);
}
}
export async function loadCredentials(): Promise<{ client_id: string; client_secret: string }> {
try {
const credentials = await loadCredentialsWithFallback();
if (!credentials.client_id || !credentials.client_secret) {
throw new Error('Client ID or Client Secret missing in credentials.');
}
return {
client_id: credentials.client_id,
client_secret: credentials.client_secret
};
} catch (error) {
throw new Error(`Error loading credentials: ${error instanceof Error ? error.message : error}`);
}
}