export async function fetchGitHubTokenOwnerDetails()

in src/github/operations/auth.ts [34:114]


export async function fetchGitHubTokenOwnerDetails(octokit: Octokits, tokenConfig: GitHubTokenConfig): Promise<TokenOwner> {
    try {
        // Default GITHUB_TOKEN has limited permissions and can't read user info
        // Return well-known github-actions bot credentials to avoid unnecessary API call
        if (tokenConfig.isDefaultToken()) {
            console.log("Using default GITHUB_TOKEN - skipping token owner API call (insufficient permissions)");
            return GITHUB_ACTIONS_BOT;
        }

        // For custom tokens (PATs, GitHub App tokens), fetch owner information from API
        console.log("Using custom token - fetching token owner info");

        try {
            // Try to get user info (works for PATs)
            const {data} = await octokit.rest.users.getAuthenticated();

            console.log(`Token owner: ${data.login} (ID: ${data.id}, Type: ${data.type})`);

            // Map GitHub API types to our internal type system
            let type: TokenOwner["type"]
            if (data.type === "Bot") {
                type = "Bot";
            } else {
                type = "User";
            }

            return {
                login: data.login,
                id: data.id,
                type,
            };
        } catch (userError: any) {
            // If /user fails with "Resource not accessible", this is likely a GitHub App token
            // GitHub App tokens can't access /user endpoint
            if (userError?.status === 403 || userError?.message?.includes('Resource not accessible')) {
                console.log("⚠️  /user endpoint not accessible - trying GraphQL viewer for GitHub App token");

                try {
                    // Try GraphQL viewer query which works for GitHub App tokens
                    const graphqlResponse = await octokit.graphql<ViewerQueryResponse>(VIEWER_QUERY);

                    const { viewer } = graphqlResponse;
                    console.log(`GitHub App token owner (via GraphQL): ${viewer.login} (ID: ${viewer.databaseId})`);

                    return {
                        login: viewer.login,
                        id: viewer.databaseId,
                        type: "Bot",
                    };
                } catch (graphqlError: any) {
                    // Both /user and GraphQL failed - can't authenticate
                    const graphqlErrorMessage = graphqlError?.message || String(graphqlError);
                    console.error("GraphQL viewer query failed:", graphqlErrorMessage);

                    throw new Error(
                        `Both REST API (/user) and GraphQL (viewer) queries failed.\n\n` +
                        `REST API error: ${userError?.message || userError}\n` +
                        `GraphQL error: ${graphqlErrorMessage}`
                    );
                }
            }
            throw userError;
        }
    } catch (error) {
        console.error("Failed to fetch token owner info:", error);

        // Provide helpful error message based on error type
        const errorMessage = error instanceof Error ? error.message : String(error);

        throw new Error(
            `❌ Unable to authenticate with provided GitHub token.\n\n` +
            `Possible causes:\n` +
            `• Token is invalid or expired\n` +
            `• Token lacks required permissions (needs 'read:user' or 'user' scope for PAT)\n` +
            `• For GitHub App tokens: ensure proper installation permissions\n` +
            `• GitHub API is unavailable\n` +
            `• Rate limit exceeded\n\n` +
            `Original error: ${errorMessage}`
        );
    }
}